Unit Testing
How do you know if your
code is correct?
Testing Your Code
• Submit to AutoLab?
• Decent for education
• Does not exist outside of class
• Need a way to test code on your own
• Call your methods in a main method?
• A great start!
• Must manually check all the printed values
• Tedious for large projects
Testing Your Code
• Unit Testing!
• Write code to automate testing
Unit Testing
• Run a series of tests on your code
• Call your method with a speci c input
• Verify that it returned the correct output
• If your code returns the correct output on ALL
the tests, it passes
• If your code fails a single test, it fails
• You want your code to be correct on ALL inputs
fi
Unit Testing
Scenario
• You were given a programming task
package week2;
• "Write a method named addFive that public class Adder {
public static int addFive(int x){
takes an int as a parameter and }
return x+5;
returns the input plus ve as an int" }
• You write this wonderful code and you
want to test it to make sure it's correct
fi
Unit Testing
Scenario package week2;
public class Adder {
• You write a main method public static int addFive(int x){
}
return x+5;
• You call your method a few times public static void main(String[] args) {
[Link](addFive(2));
[Link](addFive(5));
[Link](addFive(1));
• You print the return values to the screen
}
}
• You verify with your eyes that what was 7
10
printed makes sense 6
• You feel great about the results!
Unit Testing
• But what do you do when the the code package week2;
public class Adder {
is harder to verify like this public static int addFive(int x){
return x+5;
}
• "Write a method that sorts 100s of public static void main(String[] args) {
[Link](addFive(2));
Songs by title or artist"
[Link](addFive(5));
[Link](addFive(1));
}
• We want to move on to automated
}
testing 7
10
6
• Write testing code
• Run that code to test your method
Unit Testing
package week2;
import [Link];
package week2;
import static [Link];
public class Adder {
public class AddTest {
public static int addFive(int x){
@Test
return x+5;
public void testAddFive() {
}
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
}
assertTrue([Link](1) == 6);
}
• Let's look at our rst unit test
• Testing will be de ned in a separate le/class
fi
fi
fi
Unit Testing
package week2;
import [Link];
package week2;
import static [Link];
public class Adder {
public class AddTest {
public static int addFive(int x){
@Test
return x+5;
public void testAddFive() {
}
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
}
assertTrue([Link](1) == 6);
}
• We will use the JUnit library for testing
• JUnit does not come with java and is installed using the [Link]
le included in the project code (IntelliJ installs this automatically)
fi
Unit Testing
package week2;
import [Link];
package week2;
import static [Link];
public class Adder {
public class AddTest {
public static int addFive(int x){
@Test
return x+5;
public void testAddFive() {
}
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
}
assertTrue([Link](1) == 6);
}
• We'll use a method from this library called assertTrue which must be imported
• import static: We want to import a static method from a class without
importing the entire class - avoid typing [Link]
Unit Testing
package week2;
import [Link];
package week2;
import static [Link];
public class Adder {
public class AddTest {
public static int addFive(int x){
@Test
return x+5;
public void testAddFive() {
}
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
}
assertTrue([Link](1) == 6);
}
• Each test you write will be de ned by a public method (Note: Not
a static method)
• To tell JUnit that the method de nes a test, annotate it with @Test
fi
fi
Unit Testing
package week2;
import [Link];
package week2;
import static [Link];
public class Adder {
public class AddTest {
public static int addFive(int x){
@Test
return x+5;
public void testAddFive() {
}
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
}
assertTrue([Link](1) == 6);
}
• The @Test annotation must be included
• Common cause of errors is to miss this annotation
Unit Testing
package week2;
import [Link];
package week2;
import static [Link];
public class Adder {
public class AddTest {
public static int addFive(int x){
@Test
return x+5;
public void testAddFive() {
}
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
}
assertTrue([Link](1) == 6);
}
• Each test method has a name which will be the name of that test
• In this course - These names will appear in AutoLab to give you
more information about your tests
Unit Testing
package week2;
import [Link];
package week2;
import static [Link];
public class Adder {
public class AddTest {
public static int addFive(int x){
@Test
return x+5;
public void testAddFive() {
}
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
}
assertTrue([Link](1) == 6);
}
• Finally, we can write test cases
• A test case tests a single input/output pair
• This test class contains one test that has 3 test cases
Unit Testing
package week2;
import [Link];
package week2;
import static [Link];
public class Adder {
public class AddTest {
public static int addFive(int x){
@Test
return x+5;
public void testAddFive() {
}
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
}
assertTrue([Link](1) == 6);
}
• For each test case, call assertTrue with a boolean expression that you
expect to resolve to true
• If assertTrue is ever called with a value of false, the code fails the entire
test class - We want 0 bugs in our code!
Unit Testing
package week2;
import [Link];
package week2;
import static [Link];
public class Adder {
public class AddTest {
public static int addFive(int x){
@Test
return x+5;
public void testAddFive() {
}
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
}
assertTrue([Link](1) == 6);
}
• Note: There is no main method in this le
• JUnit will use this code through it's own main method
• IntelliJ understands JUnit and gives you convenient run buttons
fi
Unit Testing
package week2;
import [Link];
package week2;
import static [Link];
public class Adder {
public class AddTest {
public static int addFive(int x){
@Test
return x+5;
public void testAddFive() {
}
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
}
assertTrue([Link](1) == 6);
}
• Is this enough testing?
• A question that can always be asked, and never fully
answered
Unit Testing
package week2;
import [Link];
package week2;
import static [Link];
public class Adder {
public class AddTest {
public static int addFive(int x){
@Test
return x+5;
public void testAddFive() {
}
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
}
assertTrue([Link](1) == 6);
}
• We have 3 small positive integers which represent
common test cases for this method
• These are simple inputs that everyone would expect
Unit Testing
package week2;
import [Link];
package week2;
import static [Link];
public class Adder {
public class AddTest {
public static int addFive_noNegatives(int x){
@Test
return [Link](x)+5;
public void testAddFive() {
}
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
}
assertTrue([Link](1) == 6);
}
• Here is an incorrect solution for the addFive method
• Our test passes this incorrect solution!
• Not enough testing
package week2;
package week2;
import [Link];
public class Adder {
import static [Link];
public static int addFive(int x){
public class AddTest { return x+5;
}
@Test
public void testAddFive() { }
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
•
assertTrue([Link](1) == 6);
}
assertTrue([Link](10) == 15);
assertTrue([Link](100) == 105); Let's add some
@Test
public void testAddFiveWithNegatives() {
uncommon cases
assertTrue([Link](-1) == 4);
• Negative inputs are a
assertTrue([Link](-5) == 0);
assertTrue([Link](-10) == -5);
assertTrue([Link](-51) == -46);
assertTrue([Link](-100) == -95);
}
}
more unusual input
that might expose a
bug in the code
package week2;
package week2;
import [Link];
public class Adder {
import static [Link];
public static int addFive(int x){
public class AddTest { return x+5;
}
@Test
public void testAddFive() { }
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
•
assertTrue([Link](1) == 6);
}
assertTrue([Link](10) == 15);
assertTrue([Link](100) == 105); We can group our test
@Test
public void testAddFiveWithNegatives() {
cases into multiple
Tests in the same class
assertTrue([Link](-1) == 4);
assertTrue([Link](-5) == 0);
assertTrue([Link](-10) == -5);
assertTrue([Link](-51) == -46);
•
assertTrue([Link](-100) == -95);
}
Annotate each test
}
with @Test
package week2;
package week2;
import [Link];
public class Adder {
import static [Link];
public static int addFive(int x){
public class AddTest { return x+5;
}
@Test
public void testAddFive() { }
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
package week2;
assertTrue([Link](1) == 6);
assertTrue([Link](10) == 15);
public class Adder {
assertTrue([Link](100) == 105);
}
public static int addFive_noNegatives(int x){
return [Link](x)+5;
@Test
}
public void testAddFiveWithNegatives() {
assertTrue([Link](-1) == 4);
}
assertTrue([Link](-5) == 0);
•
assertTrue([Link](-10) == -5);
assertTrue([Link](-51) == -46);
assertTrue([Link](-100) == -95);
This test class:
}
} • Passes the correct solution
• Rejects this incorrect solution
package week2;
import [Link]; public static int addFive_badOnZero(int x) {
if(x > 0){
import static [Link]; return [Link](x) + 5;
}else if(x < 0){
public class AddTest { return -[Link](x) + 5;
}else{
@Test return x;
public void testAddFive() { }
assertTrue([Link](2) == 7); }
assertTrue([Link](5) == 10);
•
assertTrue([Link](1) == 6);
assertTrue([Link](10) == 15);
assertTrue([Link](100) == 105);
And passes this incorrect solution
}
@Test
•
public void testAddFiveWithNegatives() {
assertTrue([Link](-1) == 4);
assertTrue([Link](-5) == 0);
Not enough testing!
•
assertTrue([Link](-10) == -5);
assertTrue([Link](-51) == -46);
assertTrue([Link](-100) == -95);
Your tests should be able to
}
identify an incorrect solution by
}
containing at least one test case
where the solution fails
package week2;
package week2;
import [Link];
public class Adder {
import static [Link];
public static int addFive(int x){
public class AddTest { return x+5;
}
@Test
public void testAddFive() { }
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
assertTrue([Link](1) == 6);
assertTrue([Link](10) == 15);
assertTrue([Link](100) == 105); • We also want to check the edge
cases
}
@Test
•
public void testAddFiveWithNegatives() {
assertTrue([Link](-1) == 4);
assertTrue([Link](-5) == 0);
These are any inputs that can
assertTrue([Link](-10) == -5);
assertTrue([Link](-51) == -46);
expose unique bugs in the code
assertTrue([Link](-100) == -95);
}
• Typical edge case inputs: 0, "",
an empty ArrayList, an empty
@Test
public void testAddFiveEdgeCase() {
assertTrue([Link](0) == 5);
} HashMap
}
package week2;
package week2;
import [Link];
public class Adder {
import static [Link];
public static int addFive(int x){
public class AddTest { return x+5;
}
@Test
public void testAddFive() { }
assertTrue([Link](2) == 7);
assertTrue([Link](5) == 10);
assertTrue([Link](1) == 6);
assertTrue([Link](10) == 15);
assertTrue([Link](100) == 105); • Your goal when testing:
•
}
Write at least one test case that will
@Test
public void testAddFiveWithNegatives() { expose any possibly bug that could
assertTrue([Link](-1) == 4);
assertTrue([Link](-5) == 0); exist in the code being tested
assertTrue([Link](-10) == -5);
}
assertTrue([Link](-51) == -46);
assertTrue([Link](-100) == -95); • Unsure exactly how to do that?
@Test
public void testAddFiveEdgeCase() {
• Write LOTS of tests!
}
assertTrue([Link](0) == 5);
• Testing will often contain more code
}
than what's being tested!
Testing in CSE116
Testing in CSE116
• When a programming task requires test, your tests are ran:
• Against a correct solution stored on the server
• Against a variety of incorrect solutions stored on the server
• Your test suite must pass the correct solution
• If your tests reject the correct solution, there is something wrong with what
you're testing that you must correct before moving on
• Your test suite should fail all the incorrect solutions
• Your tests should be thorough enough to correctly fail/reject every incorrect
solution
• It is enough to have a single test case fail a solution to reject the entire solution
Testing Tips
@Test
public void testAddFiveEdgeCase() { • assertTrue is very
versatile
assertTrue([Link](0) == 5);
}
• Behaves like a
conditional
• You can test any
boolean expression
you can write
Testing Tips
@Test
public void testAddFiveEdgeCase() { • If you are checking 2
}
assertTrue([Link](0) == 5);
values for equality
@Test • It's better to use
public void testAddFiveEdgeCase_withAssertEquals() {
int result = [Link](0); assertEquals
assertEquals(5, result);
}
• Takes 2 arguments and
passes if they are
equivalent
• Provides helpful output
if the test case fails
Testing Tips
@Test
public void testAddFiveEdgeCase() { • You can add hint text to
}
assertTrue([Link](0) == 5);
any test case
@Test
• Add a argument that's a
public void testAddFiveEdgeCase_withAssertEquals() {
int result = [Link](0);
String before all other
}
assertEquals(5, result);
arguments
@Test
• This String is printed if the
public void testAddFiveEdgeCase_withHintText() { test case fails
int result = [Link](0);
}
assertEquals("Expected 5 on input 0, got: " + result, 5, result);
• Gives you a hint of where
to look for the bug