使用 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;
}
我要测试的是两件事:
当车牌列表中已有该车牌号的车时,成功抛出IllegalStateException异常
成功添加一辆车到列表中
我单独使用 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
,它将被返回。
我目前正在尝试使用 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;
}
我要测试的是两件事:
当车牌列表中已有该车牌号的车时,成功抛出IllegalStateException异常
成功添加一辆车到列表中
我单独使用 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
,它将被返回。