我需要使用Junit / Mockito测试此方法。 实际上,我无法使用Mockito正确编写测试,因此我使用了自己的输入来代替模拟扫描仪。我不知道我是否做对了。 (任何人都知道如何使用Mockito做到这一点吗?)
这是我要测试的方法:
public RentingACar rentACar(Scanner input) {
RentingACar rentingACar = new RentingACar();
System.out.print("Brand: ");
rentingACar.setBrand(input.next());
System.out.print("Name: ");
rentingACar.setName(input.next());
System.out.print("Surname: ");
rentingACar.setSurname(input.next());
System.out.print("Rent Date: ");
rentingACar.setRentDate(input.next());
System.out.print("Client number: ");
rentingACar.setClientNumber(input.nextInt());
return rentingACar;
}
这是我的考试:
@Test
void rentACar() {
Scanner scanner = new Scanner("Mazda\nPeter\nParker\n20.02\n1234");
ClientDataGetter clientDataGetter = new ClientDataGetter();
RentingACar rentingACar = clientDataGetter.rentACar(scanner);
assertNotNull(rentingACar);
assertEquals("Mazda", rentingACar.getBrand());
assertEquals("Peter", rentingACar.getName());
assertEquals("Parker", rentingACar.getSurname());
assertEquals("20.02", rentingACar.getRentDate());
assertEquals(1234, rentingACar.getClientNumber());
}
这有意义吗?
答案 0 :(得分:1)
为什么在不需要Mockito时要使用它,地狱,使用Mockito编写代码比没有Mockito时要麻烦得多? Mockito是完全不得已的选择(例如,模拟数据库或外部服务),即使这样,是否应使用它还是值得怀疑的(而不是仅仅编写自己的FakeDatabase
或FakeExternalService
)。这里绝对不需要,被嘲笑的Scanner
还能提供什么帮助?
即使您要测试的代码有很多不足之处,我也会说您的方法很好。因为这个问题是关于测试的,所以我不会谈论代码本身。
您仅测试了所谓的快乐路径,这表示输出完美无缺且一切正常的情况。
您还需要测试边缘情况(输入为最大/最小时,例如L.MIN_VALUE / 0 / Long.MAX_VALUE以数字表示,0以String表示长度等),例如用空/一个字母名称,客户编号以0开头。
毕竟,您需要测试输入是否仅仅是错误的:没有\n
符号,没有日期应该是日期的等等,这里有很多可能性。您可能会发现代码还不够,您将不得不对其进行更改(也许添加一些输入验证)。这就是为什么最好从测试(测试驱动的开发)开始的原因,您可以在编写代码之前先看到必须做的验证,然后您将为此做好准备。这是简单的情况,但是向已经存在的代码中添加重要的功能并不总是那么容易,而且如果某人已经使用了该代码,甚至可能会有风险。我见过很多情况,当有人需要进行这样的修改时,但是如果没有巨大的重构是不可能的,所以这就是他们所做的(请不要做):
if(mySpecialCase) {
// all the logic
} else {
// all the logic, almost identical to the logic above
}
编辑:回复您的评论-Why is it bad practice to make if conditions?
我在这里不只是在谈论if
条件。我说的是两个if
分支中潜在的代码重复,它们很可能具有非常相似的代码。假设您要进行另一项更改,您必须在两个分支中都添加另一个if
,这会变得一团糟。
If
条件也不应过度使用,尤其是当条件归结为许多不同的分支时。仅通过查看代码就很难调试,测试和查看正在发生的事情。一定要有人(或您)通过查看并分析代码来了解代码的作用,这一点非常重要。解决这个问题通常并不容易,需要使用一些design patterns,例如decorator,有时甚至是一个简单的switch也会有很大帮助。
答案 1 :(得分:1)
这就是我使用Mockito编写测试的方式。
import org.junit.Test;
import java.util.Scanner;
import static org.mockito.Mockito.*;
public class ClientDataGetterTest {
ClientDataGetter clientDataGetter = new ClientDataGetter();
@Test
public void testRentACar() {
// define input data (test Scanner object)
Scanner scanner = new Scanner("Mazda\nPeter\nParker\n20.02\n1234");
// call you method
RentingACar rentACar = spy(new RentingACar());
clientDataGetter.rentACar(rentACar, scanner);
// Verify that the methods were called with exact parameter values and exactly one time each
verify(rentACar, times(1)).setBrand("Mazda");
verify(rentACar, times(1)).setName("Peter");
verify(rentACar, times(1)).setSurname("Parker");
verify(rentACar, times(1)).setRentDate("20.02");
verify(rentACar, times(1)).setClientNumber(1234);
// Old code
/*
//check the results
assertEquals("Mazda", rentingACar.getBrand());
assertEquals("Peter", rentingACar.getName());
assertEquals("Parker", rentingACar.getSurname());
assertEquals("20.02", rentingACar.getRentDate());
assertEquals(1234, rentingACar.getClientNumber());
*/
}
Mockito正在确保您的二传手被叫住。
我个人认为,如果您的RentingACar看起来像一个简单的POJO,那么就不需要像我一样模拟它了,您的方法就可以了。
您可以通过如下定义Mockito for Scanner://为扫描器定义模拟
Scanner scanner = mock(Scanner.class);
when(scanner.next()).thenReturn("Mazda","Peter","Parker","20.02","1234");
,但是模仿者不能模仿最终课程。标准的java.util.Scanner是最终类。