Skip to content

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 the org.junit.jupiter.api.Test class.
  • 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.
  • Each test method uses assertEquals (or other assert methods provided by JUnit) to verify correctness.
    • The assertEquals method belongs to the org.junit.jupiter.api.Assertions class. The import static statement allows you to call these methods directly, without having to specify the Assertions class name.

Tip

Skim the Assertions documentation to see how many methods are available.

Step 1. Getting Started

Do the following steps in VS Code:

  1. Create a lab05 folder under your src/labs folder.
  2. Create a file named CarTest.java (under lab05).
  3. Write the package and public class statements.
  4. Write a Javadoc comment with your name and date.
  5. Add the following lines (at the top) to import JUnit:
    import static org.junit.jupiter.api.Assertions.assertEquals;
    
    import org.junit.jupiter.api.Test;
    
  6. Add this line to import your Car class from Lab 3:
    import labs.lab03.Car;
    
    Car.java must be in the labs/lab03 folder for this import to work. If you don't have a Car 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():

  1. Create two Car objects.
    • Each car should have a different make and year.
  2. 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:

  1. Create a Car object.
  2. 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.
  3. Call the brake() method.
    • Assert that the Car object's speed is now 0.

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:

  1. Create a Car object.
  2. Call the brake() method.
    • Assert that the Car object's speed is 0.
  3. 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.
  4. 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.

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:

  1. Create four Car objects.
    • car1 and car2 should have the same make and year.
    • car3 should have a different make but the same year as car1 (and car2).
    • car4 should have the same make but a different year as car1 (and car2).
  2. Compare four Car objects.
    • car1 should "equals" car2.
    • car1 should not "equals" the other two cars.
  3. Compare car1 with a different type of object (in this case, a String):
    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():

  1. Create a Car object.
  2. 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