摆弄Mockito来实施我的服务的单元测试但由于某种原因我无法通过我厚厚的头骨得到这个。我的测试正在通过,但我不相信我做得对。
这是我测试count()方法的一个例子。该方法只是将调用转发到其存储库,我不想验证只有那个,没有其他事情发生。这就是我所拥有的:
@RunWith(MockitoJUnitRunner.class)
public class PersonServiceImplTest {
@Mock
private PersonRepository personRepository;
@InjectMocks
private PersonServiceImpl personService;
@Test
public void testCount() {
when(personRepository.count()).thenReturn(2L);
long count = personService.count();
assertEquals(2L, count);
verify(personRepository).count();
}
}
我的测试正在通过,但我有一些问题。
谢谢
是的,你做得对。
您正在将模拟存储库注入到真实服务中,然后测试该服务。当涉及到服务中的业务逻辑时,任何事情都可能发生。这就是为什么用已知输入和已知输出验证代码很重要,就像你正在做的那样。
return 2L
。 assertEquals会通过,但验证会失败。2L
没有什么意义,但是测试您的服务返回2L
是一个很好的例子。类似地,测试服务方法已经被调用没有意义,但是测试存储库方法已被调用的情况很好。您现在拥有测试服务的工具,下一步是确定要编写哪些测试。
为了:
assertEquals()
:这取决于。 personRepository.count()
在返回之前对personService
的结果有什么影响,有可能改变它的价值吗?如果答案是“肯定不是”,那么你可能不需要assertEquals()
- 但如果有任何可能出现问题的机会,那么assertEquals()
将确保它没有。verify()
:这取决于。 personRepository.count()
有没有被召唤的机会?或者它被不止一次调用(默认情况下verify()
期望它的参数只被调用一次)?如果没有,那么你可能不需要它。personRepository.count()
看起来像
public int count() {
return this.personService.count();
}
如果是这样,你可能根本不需要太多的测试。如果你坚持进行测试,跳过verify()
可能没问题,因为上面的方法没有其他方法来获取值,而不是通过调用函数verify
ing,它返回该值,因此它几乎不能称之为一旦。
另一方面,如果您的功能如下:
public int count() {
// get a personService from an injector
// log the personService's details
// generate a random number
// try calling count() on personService, catch an error
// if you caught the error, return the random number
}
那么也许你真的想要verify()
,因为突然之间,有很多事情正在发生,其中一些(即随机数)可能会被混淆,即使出现可怕的错误。
最好通过构造函数而不是PersonRepository
注入@InjectMocks
。这也消除了对特定运行器的需求(或者,在测试的后期,涉及Spring进行低级别测试)。
你对Mockito的使用是正确的但不是最佳的。您确实需要assertEquals
,因为您正在测试的是该服务返回的值与您从存储库中提供的值相同。 verify...count
不是必需的,因为它通过检查是否返回了适当的值来暗示。你可以通过返回一个随机数而不是2
来改善这一点。
还要检查是否真的值得将count()
包装在另一个对象中,或者只是添加不必要的图层。
最后,您可以考虑检查Spock;它是基于Groovy的测试语言,位于JUnit之上,提供了一种干净而强大的模拟语言。