摆弄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();
}
}
我的考试通过了,但是我有一些疑问。
是否需要assertEquals?据我了解,无论我将什么作为方法存根(.thenReturn(value ..))的预期结果,都将始终是返回的值。还是在这种情况下还可以呢?
我需要验证吗?我感觉像是在做,因为我想验证是否确实调用了personRepository.count()。或者当我也有assertEquals()时,这是否多余?
我是否需要assertEquals并进行验证?
最后,我是否正确:)
谢谢
答案 0 :(得分:3)
顺序:
是否需要assertEquals()
:这取决于。在返回之前,personRepository.count()
中personService
的结果是否有做任何改变其值的可能性?如果答案是“肯定不是”,那么您可能不需要assertEquals()
-但是如果有可能出现问题,那么assertEquals()
将确保没有问题。
您是否需要verify()
:这取决于。是否有可能没有呼叫personRepository.count()
?还是它被多次调用(默认情况下,verify()
期望其参数被精确调用一次)?如果没有,那么您可能不需要它。
您是否同时需要:(取决于模式)。见上文:他们做了不同的事情。在很多情况下,您都希望同时检查这两种情况:1.返回正确的结果,并且2.通过执行您期望做的事情来返回结果。
您这样做正确吗?嗯...这取决于。 personRepository.count()
看起来像
public int count() {
return this.personService.count();
}
如果是这样,您可能根本不需要太多测试。如果您坚持要进行测试,则跳过verify()
可能没问题,因为上述方法除了调用函数之外,没有获取值的其他方式 ing,它会返回该值,因此几乎不能多次调用它。
另一方面,如果您的函数如下所示:
verify
然后也许您要做,想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
}
,因为突然之间,发生了很多事情,其中某些事情(即随机数)可能会被误认为是正确的即使出现严重错误也可以正常运行。
答案 1 :(得分:2)
是的,您做对了。
您要将模拟存储库注入到真实服务中,然后测试该服务。当涉及到服务中的业务逻辑时,可能会发生任何事情。这就是为什么像您正在做的那样,用已知的输入和已知的输出来验证代码很重要的原因。
给定存储库的响应,您正在检查业务逻辑的结果。这个特定的代码相当简单,但是可以想象一下,如果业务逻辑是提供一个平均值或总和,而不仅仅是从存储库中提供的相同值。
和3.验证和assertEquals正在测试不同的事物。验证检查您的存储库方法是否被调用,断言检查服务是否以正确的值响应。想象一下,您的服务方法具有硬编码的return 2L
。 assertEquals将通过,但验证将失败。
是的,您做对了。您要测试的内容与您要测试的原因有关。是否需要特定的断言或验证通常取决于具体情况。在这种情况下,测试您的存储库方法返回2L
毫无意义,但是测试您的服务返回2L
是一个很好的案例。同样,测试服务方法已被调用没有任何意义,但是有一个很好的例子来测试存储库方法已被调用。
您现在有了测试服务的工具,下一步是确定要编写的测试。
答案 2 :(得分:0)
最好通过构造函数而不是mvn install -Dmaven.test.skip=true
注入PersonRepository
。这也消除了对特定运行器的需求(或者,在您的测试后期,涉及Spring的低级测试)。
您对Mockito的使用是正确,但不是最佳选择。您确实需要@InjectMocks
,因为要测试的是服务返回的值与您从存储库提供的值相同。 assertEquals
是不必要的,因为它通过检查是否返回了适当的值来隐含。您可以通过返回随机数而不是verify...count
来改善这一点。
还要检查将2
包装在另一个对象中是否真的值得,或者是否只是添加不必要的层。
最后,您可以考虑检查Spock;它是JUnit之上基于Groovy的测试语言,提供了一种干净而强大的模拟语言。