Lab 4: Car Class and Test

In this lab, you will implement a Car class and corresponding CarTest. You will learn about non-static attributes and methods.

Learning Objectives

After completing this lab, you should be able to:

  • Interpret a UML class diagram and stub out the corresponding code.
  • Write tests that create objects and run both static and non-static methods.
  • Incrementally implement and test non-static methods from stubs.

Step 1. Getting Started

Do the following steps in VS Code:

  1. Create a lab04 folder under your src/ folder.
  2. Add two new files: Car.java and CarTest.java.
  3. Write the package and public class statements.
  4. Write a Javadoc comment with your name and date.

When finished, your Car.java should look like this:

VS Code screenshot with Car.java

Step 2. UML Class Diagram

Based on the diagram below, declare each attribute and write a stub for each method. Do not implement any methods yet, but make the code compile. For example, if a method returns a String, write return ""; as a stub (placeholder). Show your code to the instructor or TA before proceeding to the next step.

UML Diagram screenshot for Car class

Note

The brake() method is void (does not return a value). The word void is usually omitted in UML class diagrams.

Step 3. Constructor, Getters

The purpose of a constructor is to initialize the attributes of this object. Notice the Car class has three attributes: make, speed, and year. The constructor has two parameters: make and year. Use the parameters to initialize this object's make and year. Initialize this object's speed to zero. Then write the Javadoc comment for the constructor.

Note

When writing documentation for constructors, do not use the word create. Constructors do not "create" objects; the new operator creates an object. Once an object has been created, the constructor is called to initialize the object.

The purpose of a getter method is to return the current value of an attribute. Notice that the attributes are private, meaning they can be accessed only in the Car class. Other classes, like CarTest, will need to use the public getters to access the attributes. Implement each getter by returning the corresponding attribute.

Javadoc comments are not required for most getter methods. However, a Javadoc comment is required if a getter does more than simply return an attribute.

Step 4. Test the Constructor

Before implementing the other methods in Car.java, let's make sure the constructor and getter methods work correctly. Open CarTest.java

We will not use unit tests for this lab, but a driver type test file.

Add the following code to CarTest.java:

Setup a main method

    public static void main(String[] args) {

    }

  1. Read through the code below and identify each of the following: - the creation of two car objects - calls to all three getters for the first car - calls to all three getters for the second car

  2. Copy the code to your main:

        System.out.println();
        System.out.println("Testing Car Constructor()");
        Car car1 = new Car("Nissan", 2003);
        Car car2 = new Car("Tesla", 2024);
        System.out.println("Car 1 make should be Nissan | " + car1.getMake());
        System.out.println("Car 1 speed should be 0.0 | " + car1.getSpeed());
        System.out.println("Car 1 year should be 2003 | " + car1.getYear());
        System.out.println("Car 2 make should be Tesla | " + car2.getMake());
        System.out.println("Car 2 speed should be 0.0 | " + car2.getSpeed());
        System.out.println("Car 2 year should be 2024 | " + car2.getYear());
        System.out.println();
Run the test by clicking the green play button for the CarTest.java file. Your output after the | pipe symbol should look like the output in front of the symbol for all of these main tests.

Step 5. Accelerate and Brake

The accelerate() method increases the current speed of the car by 5 miles per hour. After increasing the speed, accelerate() returns a string describing the change. Use the format "15.0 + 5.0 = 20.0" where 15.0 is the old speed and 20.0 is the new speed.

Note

The String.format() method is useful for formatting double values. For example, you can format the speed values to one decimal place as follows:

return String.format("%.1f + 5.0 = %.1f", speed - 5, speed);

Your code must not allow the speed to increase above 150 miles per hour. If the speed is already 150, and accelerate() is called, the speed should remain 150. In that case, the method should return the string "150.0 + 0.0 = 150.0".

The brake() method should decrease the current speed by 5 miles per hour. Your code must not allow the speed to decrease below 0 miles per hour.

Write Javadoc comments for accelerate() and brake() before moving on to the next step.

Step 6. Test Driving the Car

Add the following code to CarTest:

        System.out.println("Testing Car.accelerate() and brake()");
        Car car = new Car("Nissan", 2003);
        String result = car.accelerate();
        System.out.print("\n0.0 + 5.0 = 5.0 | ");
        System.out.print(car.getSpeed());
        car.brake();
        System.out.print("\n5.0 - 5.0 = 0.0 | ");
        System.out.print(car.getSpeed());
        System.out.println("\nTesting limits of speed");
        Car car3 = new Car("Nissan", 2003);
        // brake when already 0
        car3.brake();
        System.out.print("Car3 Braking at 0.0 speed should still be 0.0 | ");
        System.out.print(car3.getSpeed());
        // accelerate to 150
        String results = "";
        for (int i = 0; i < 30; i++) {
            results = car3.accelerate();
        }
        System.out.println("\n145.0 + 5.0 = 150.0 | " + results);
        System.out.print("Car3 speed should be 150 | ");
        System.out.print(car3.getSpeed());
        // try to go faster
        results = car3.accelerate();
        System.out.print("\n150.0 + 0.0 = 150.0 | " + results);
        System.out.print("\nCar3 speed should still be 150 | " + car3.getSpeed());

This test should do the following:

  1. Create a Car object.
  2. Call the accelerate() method.
    • Test that the method returned "0.0 + 5.0 = 5.0".
    • Test that the Car object's speed is now 5.
  3. Call the brake() method.

    • Test that the Car object's speed is now 0.
  4. Create a Car object.

  5. Call the brake() method.
    • Assert that the Car object's speed is 0.
  6. 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.
  7. 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.

Run CarTest again and make sure the tests passes.

Step 7. The equals() method

The purpose of the equals() method is to determine if two objects are equivalent. Replace your equals() method with the following solution:

@Override
public boolean equals(Object obj) {
    if (obj instanceof Car) {
        Car car = (Car) obj;
        return car.make.equals(this.make) && car.year == this.year;
    }
    return false;
}

The above code:

  1. Overrides the default implementation of equals().
    • By default, equals() returns true if this and obj are the same object.
  2. Checks if obj, which can be any type of object, is actually a Car object.
    • If not, then equals() returns false at the end.
  3. Declares a Car variable to reference the same object as obj.
  4. Determines whether car has the same make and year as this object.

Note

Javadoc comments are not required for @Override methods, because the documentation is already defined by the default implementation. In VS Code, you can hover the mouse over a method's name to see the documentation.

Step 8: The toString() method

The purpose of the toString() method is to return a string that represents the object. Replace your toString() method with the provided solution:

@Override
public String toString() {
    return String.format("A %d %s that is going %.1f mph",
        year, make, speed);
}

The above code:

  1. Overrides the default implementation of toString().
    • By default, toString() returns the class name and the memory location of the object. For example, "labs.lab04.Car@5b6f7412".
  2. Uses the String.format() method to build a string based on the object's attributes.

Step 9. Final Test and Submit

Add the following test code to CarTest:

        System.out.println();
        System.out.println("\nTesting equals and toString");
        // Test car equals
        Car car4 = new Car("Nissan", 2003);
        Car car5 = new Car("Nissan", 2003);
        Car car6 = new Car("Honda", 2003);
        Car car7 = new Car("Nissan", 2024);
        System.out.print("\ncar4 == car5 yields true  | ");
        System.out.print(car4.equals(car5));

        System.out.print("\ncar4 != car6 yields false | ");
        System.out.print(car4.equals(car6));
        System.out.print("\ncar4 != car 7 yields false | ");
        System.out.print(car4.equals(car7));
        Object obj = "car8";
        System.out.print("\ncar4 is not car8 object yields false | ");
        System.out.print(car4.equals(obj));

        // Test car toString
        Car car9 = new Car("Nissan", 2003);
        System.out.println("\nA 2003 Nissan that is going 0.0 mph");
        System.out.println(car9.toString());

        // Test car toString
        Car car10 = new Car("Toyota", 2010);
        System.out.println("\nA 2010 Toyota that is going 0.0 mph");
        System.out.println(car10.toString());

Note: 1. car4 has the same make and year. 2. car5 has a different make. 2. car6 has a different year. 4. "car7" (in quotes) is a string.

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().

As a final step, click the green play button next to public class CarTest.

Submit both Car.java and CarTest.java inside a lab04 folder to Gradescope. Points will be allocated as follows:

Criterion Points Details
Compile 0 pts Success Required
CompileOfficialTests 0 pts Success Required
Style 0 pts Success Required
OfficialTests 10 pts Partial Credit Possible