我有一个使用Spring依赖注入的Java应用程序。 我想模拟一个 bean,并验证它是否接收某些方法调用。
问题是 Mockito 不会在测试之间重置模拟,所以我无法正确验证对它的方法调用。
我的测试设备:
public class MyClass {
@Resource
SomeClientClass client;
public void myMethod() {
client.someMethod();
}
}
单元测试类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = UnitTestConfig.class)
public class MyClassTest {
@Resource
SomeClientClass client;
@Test
public void verifySomething() {
// ...
Mockito.verify(client).publish();
}
}
最后
@Configuration
public class UnitTestConfig {
@Bean
SomeClientClass client() {
return Mockito.mock(SomeClientClass.class);
}
}
虽然我可以通过在测试之间手动重置模拟来解决这个问题,但我想知道是否有一种更干净/更惯用的方法。
我必须在开始时添加以下内容:
@BeforeEach
void setup() {
Mockito.reset(...mockBeans);
...
}
作者没有解释他为什么需要它,我可以提供更多细节。以这种方式将Spring的依赖注入与Mockito相结合并不是最好的方法。
这会导致错误,因为相同的模拟将在不同的测试之间重复使用!这意味着 verify() 将无法正常工作。它将累积来自不同测试的方法调用。例如,你会得到"通缉 1 次:"-"但被通缉 2 次"。
Mockito中最通用的解决方案是使用@InjectMocks。此注释执行 2 件重要操作:
- 实际上将所有@Mock字段注入到用 @InjectMocks 注释的类中
- 重置每个@Mock带注释的类。 (因此,verify() 不会累积来自不同测试的调用)
代码示例:
@RunWith(MockitoJUnitRunner.class)
public class SomeSpringConverterTest {
@InjectMocks
private SomethingToJsonNodeSpringConverter someSpringConverter;
@Mock
private SomethingDatamodelService someDatamodelService;
@Test
public void convertOriginalContainerTest() {
SomethingContainer someContainer = buildSomeContainer("aa", "bb");
Mockito.when(someDatamodelService.getAttributes()).thenReturn(Arrays.asList("aa", "bb"));
JsonNode node = someSpringConverter.convert(someContainer, JsonNode.class);
Mockito.verify(someDatamodelService.getAttributes());
assertTrue(node.get("aa") != null);
}
@Test
public void convertOriginalContainerTest() {
SomethingContainer someContainer = buildSomeContainer("aa", "bb");
Mockito.when(someDatamodelService.getAttributes()).thenReturn(Arrays.asList("aa", "bb"));
JsonNode node = someSpringConverter.convert(someContainer, JsonNode.class);
Mockito.verify(someDatamodelService.getAttributes());
assertTrue(node.get("bb") != null);
}
}