Lab 5: Testing with JUnit¶
In this lab, you will implement a CarTest class that tests the Car class from Lab 4.
You will gain experience with JUnit and code coverage.
Learning Objectives¶
After completing this lab, you should be able to:
- Write JUnit tests that create objects and assert non-static methods.
- Run JUnit tests in VS Code (from the test class and Testing activity).
- Analyze code coverage results to find out which lines are not tested.
Introduction to JUnit¶
JUnit is a widely used open-source testing framework for Java. When writing tests, developers generally follow a basic pattern:
- For every class C, there is a class named
CTestfor testing the C class. - For every method m, there is a method named
testMfor testing the m method. - Additional test methods can be written to test specific requirements.
Compare the "Main Class" and "Test Class" examples below (click to open):
Main Class
public class BasicMath {
public static int add(int x, int y) {
int sum;
sum = x + y;
return sum;
}
public static int subtract(int x, int y) {
int diff;
diff = x - y;
return diff;
}
}
Test Class
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
public class BasicMathTest {
@Test
public void testAdd() {
int expect;
int actual;
expect = 15;
actual = BasicMath.add(7, 8);
assertEquals(expect, actual);
}
@Test
public void testSubtract() {
int expect;
int actual;
expect = 2;
actual = BasicMath.subtract(3, 1);
assertEquals(expect, actual);
}
}
Notice in the above examples:
- Test methods are
void, non-static, and have no parameters.- The
@Testlines are annotations that tell JUnit which methods should be run as tests. A class might have other (helper) methods that aren't considered tests. To use@Test, you must import theorg.junit.jupiter.api.Testclass.
- The
- Each test method establishes an expected value and runs the corresponding method to get the actual value.
- In the above example, we expect that 7 + 8 will be 15, and that 3 - 1 will be 2.
The actual values (15 and 2) should be what the methods in
BasicMathreturn.
- In the above example, we expect that 7 + 8 will be 15, and that 3 - 1 will be 2.
The actual values (15 and 2) should be what the methods in
- Each test method uses
assertEquals(or other assert methods provided by JUnit) to verify correctness.- The
assertEqualsmethod belongs to theorg.junit.jupiter.api.Assertionsclass. Theimport staticstatement allows you to call these methods directly, without having to specify theAssertionsclass name.
- The
Tip
Skim the Assertions documentation to see how many methods are available.
Step 1. Getting Started¶
Do the following steps in VS Code:
- Create a
lab05folder under yoursrc/labsfolder. - Create a file named
CarTest.java(underlab05). - Write the
packageandpublic classstatements. - Write a Javadoc comment with your name and date.
- Add the following lines (at the top) to import JUnit:
import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; - Add this line to import your
Carclass from Lab 3:import labs.lab03.Car;Car.javamust be in thelabs/lab03folder for this import to work. If you don't have aCarclass, please download the solution from Canvas.
Step 2. Test the Constructor¶
For the first test, we'll make sure the constructor and getter methods work correctly.
Add the following method to CarTest:
@Test
public void testConstructor() {
}
Add the following code to testConstructor():
- Create two
Carobjects.- Each car should have a different make and year.
- Write three
assertEqualsstatements for each car:getMake()should return the make you chose.getSpeed()should return zero (at this point).getYear()should return the year you chose.
Run the test by clicking the green play () button next to the method. If the test fails, make whatever changes are necessary in your code. After the test passes, right-click the green play button and select "Run with Coverage".
In Car.java, the constructor and getters should be highlighted in green, meaning those lines were executed during the test.
The other methods should be highlighted in red, meaning they were not executed during the test.
Close the "Test Coverage" window (lower left corner of VS Code) to clear coverage results.
Tip
Tests can also be run from the "Test Explorer" (the large icon) on the left side of VS Code.
Step 3. Test Driving the Car¶
Add the following method to CarTest:
@Test
public void testAcceleration() {
}
This test should do the following:
- Create a
Carobject. - Call the
accelerate()method.- Assert that the method returned
"0.0 + 5.0 = 5.0". - Assert that the
Carobject's speed is now 5.
- Assert that the method returned
- Call the
brake()method.- Assert that the
Carobject's speed is now 0.
- Assert that the
Run the test and make sure the test passes.
Then run the test again with coverage.
Some lines of Car.java are green, some are yellow, and some are red.
You still need to test accelerating when speed is 150 and braking when speed is 0.
Add the following method to CarTest:
@Test
public void testSpeedLimits() {
}
This test should do the following:
- Create a
Carobject. - Call the
brake()method.- Assert that the
Carobject's speed is 0.
- Assert that the
- Call the
accelerate()method 30 times, and then:- Assert that the method returned
"145.0 + 5.0 = 150.0". - Assert that the
Carobject's speed is now 150.
- Assert that the method returned
- Call the
accelerate()method one more time.- Assert that the method returned
"150.0 + 0.0 = 150.0". - Assert that the
Carobject's speed is still 150.
- Assert that the method returned
At this point, your tests should have full coverage of the accelerate() method.
Step 4. equals() and toString()¶
Add the following test methods to CarTest:
@Test
public void testEquals() {
}
@Test
public void testString() {
}
The first method should do the following:
- Create four
Carobjects.car1andcar2should have the samemakeandyear.car3should have a differentmakebut the sameyearascar1(andcar2).car4should have the samemakebut a differentyearascar1(andcar2).
- Compare four
Carobjects.car1should "equals"car2.car1should not "equals" the other two cars.
- Compare
car1with a different type of object (in this case, aString):assertFalse(car1.equals("car1"));
Calling the equals() method four times is necessary to cover all the branches.
In contrast, the toString() method does not have any branches.
So only one method call is necessary to get full coverage of toString():
- Create a
Carobject. - Call the
toString()method, and assert that the result is correct.
Step 5. Final Test and Submit¶
Click the green play () button next to public class CarTest.
All five tests should pass, and you should have 100% code coverage of the Car class.
Submit only CarTest.java to Gradescope.
Your code will compile and run with the Car.java sample solution.
Points will be allocated as follows:
| Criterion | Points | Details |
|---|---|---|
| Compile | 0 pts | Success Required |
| CompileOfficialTests | 0 pts | Success Required |
| Style | 0 pts | Success Required |
| SelfTests | 2 pts | Partial Credit Possible |
| Coverage | 4 pts | Partial Credit Possible |
| OfficialTests | 4 pts | Partial Credit Possible |