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
CTest
for testing the C class. - For every method m, there is a method named
testM
for 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
@Test
lines 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.Test
class.
- 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
BasicMath
return.
- 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
assertEquals
method belongs to theorg.junit.jupiter.api.Assertions
class. Theimport static
statement allows you to call these methods directly, without having to specify theAssertions
class 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
lab05
folder under yoursrc/labs
folder. - Create a file named
CarTest.java
(underlab05
). - Write the
package
andpublic class
statements. - 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
Car
class from Lab 3:import labs.lab03.Car;
Car.java
must be in thelabs/lab03
folder for this import to work. If you don't have aCar
class, 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
Car
objects.- Each car should have a different make and year.
- Write three
assertEquals
statements 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
Car
object. - Call the
accelerate()
method.- Assert that the method returned
"0.0 + 5.0 = 5.0"
. - Assert that the
Car
object's speed is now 5.
- Assert that the method returned
- Call the
brake()
method.- Assert that the
Car
object'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
Car
object. - Call the
brake()
method.- Assert that the
Car
object'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
Car
object'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
Car
object'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
Car
objects.car1
andcar2
should have the samemake
andyear
.car3
should have a differentmake
but the sameyear
ascar1
(andcar2
).car4
should have the samemake
but a differentyear
ascar1
(andcar2
).
- Compare four
Car
objects.car1
should "equals"car2
.car1
should not "equals" the other two cars.
- Compare
car1
with 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
Car
object. - 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 |