使用 Mockito 测试方法的正确方法是什么?

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

我目前正在尝试使用 Mockito 测试一个方法,但我卡在了某个方法上。

例如,有 class 称为 Car 和 CarSystem。

汽车 class 包含两个参数,名称 (String) 及其车牌 (String) 及其 getter/setter 方法。

我尝试使用 Mockito 测试的方法是一个名为 addCar 的方法,它位于 CarSystem class。

汽车系统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;
    }

我要测试的是两件事:

  1. 当车牌列表中已有该车牌号的车时,成功抛出IllegalStateException异常

  2. 成功添加一辆车到列表中

我单独使用 JUnit 所做的是:

@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");
    }

但我不知道如何使用 Mockito 测试它们...任何人都可以帮助我或给我一些提示吗?

P.S) 我可以自由更改 classes 的内容以进行 Mockito 测试。

我不会创建要在方法中添加的 Car,而是将其作为参数传入,即

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

由于您正在测试服务本身,因此您不能模拟它 - 只能模拟汽车。由于 Car 您访问的唯一数据是 getPlateNumber,因此测试看起来像这样:

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);
    }
}

您不能真正独立地测试 add 和 get,因为它们彼此不变量: 1. 如果使用具有新车牌号的汽车调用 add,则随后的 get 给出车牌号将检索它,并且 2. 如果使用 Car 的车牌号调用 get,之前已为其调用过 add,它将被返回。