seung
seung

Reputation: 65

What is a proper way of testing a method using Mockito?

I am currently trying to test a method using Mockito and I am stuck on a certain method.

For example, there are classes called Car and CarSystem.

The car class contains two parameters, Name(String) and its License Plate(String) and their getter/setter methods.

The method I am trying to test using Mockito is a method called, addCar which is in the CarSystem class.

CarSystem class:

private final List<Car> cars= new ArrayList<>();

public Car addCar(String name, String plateNumber) throws IllegalStateException {
        Car clash = getCar(plateNumber);
        if (null != clash) throw new IllegalStateException("Car with that Number already exists");

        Car car = new Car(name, plateNumber);
        cars.add(car);

        return car;
    }


public Car getCar(String match) {
        for (Car car: cars) {
            if (car.getPlateNumber().equals(match)) return car;
        }

        return null;
    }

What I am trying to test is the two things:

  1. It successfully throws an IllegalStateException exception when there is a car with the plate number that already exists in the car list.

  2. It successfully adds a car to the list.

What I did solely using JUnit is:

@Test
    public void testAddCar_ThrowingException() {

        try {

            CarSystem sys = new CarSystem();
            Car car = sys.addCar("1234", "Toyota123");
            Car car1= sys.addCar("1234", "Honda123");
            Assert.fail();
        } catch(IllegalStateException e) {
            System.out.println(e);
        }
    }

@Test
    public void testAddCar() {

            CarSystem sys = new CarSystem();
            Car car = sys.addCar("1234", "Toyota123");
            Assert.assertEquals(sys.getCar(1234).getName(), "Toyota123");
    }

But I have no idea how to test them using Mockito... Can anyone please help me or give me a hint about this?

P.S) I can freely change the content of the classes for Mockito test.

Upvotes: 0

Views: 114

Answers (1)

daniu
daniu

Reputation: 14999

I would not create the Car to be added inside the method but have it passed in as a parameter, ie

interface CarService {
  Car addCar(Car toAdd);
  Car getCar(String plateNumber);
}

Since you are testing the service itself, you cannot mock it - only the car. Since the Car's only data you access is getPlateNumber, a test would look something like this:

class ScratchTest {
    private CarService sut;

    @Before
    public void before() {
        sut = new CarService();
    }

    @Test
    public void addSucceeds() {
        String plateNumber = "new";
        Car toAdd = mock(Car.class);
        when(toAdd.getPlateNumber()).thenReturn(plateNumber);
        Car added = sut.addCar(toAdd);

        // assert return value
        assertSame(toAdd, added);
        // assert car now available via get
        Car stored = sut.getCar(plateNumber);
        assertSame(toAdd, stored);
    }

    @Test(expected = IllegalArgumentException.class)
    public void addFails() {
        Car existing = mock(Car.class);
        String plateNumber = "existing";
        when(existing.getPlateNumber()).thenReturn(plateNumber);
        sut.addCar(existing);
        Car toAdd = mock(Car.class);
        when(toAdd.getPlateNumber()).thenReturn(plateNumber);

        sut.addCar(toAdd);
    }
}

You cannot really test add and get independently, because they are invariants of each other: 1. If add is called with a car with a new plate number, a subsequent get given that plate number will retrieve it, and 2. If get is called with the plate number of a Car for which add has been called before, it will be returned.

Upvotes: 1

Related Questions