似乎返回 void 的模拟bean 在测试对象内部调用时不会抛出错误。我可以在外面调用它,但它会抛出错误。我的使用方式有问题吗?
//some imports ...
@RunWith(SpringRunner.class)
@SpringBootTest(classes={ MessagingController.class })
public class MessagingControllerTest {
@Autowired
private MessagingController controller;
@MockBean
private RabbitMessagingTemplate rabbitMessagingTemplate;
@Test
public void testPublishMessageConversionException() {
//given:
Message message = new Message(null, null, null);
//when:
doThrow(MessageConversionException.class).when(rabbitMessagingTemplate).convertAndSend(any());
ResponseEntity<?> response = controller.publish(message);
// rabbitMessagingTemplate.convertAndSend() // this throws the error
//then:
assertThat(response).isNotNull();
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
verify(rabbitMessagingTemplate).convertAndSend(message.getExchange(), message.getRoutingKey(), message.getPayload());
}
...
}
如果你只是想进行单元测试,为什么要使用整个 spring 上下文?在我看来,SpringRunner 对于集成和 e2e 测试非常有用,但对于单元测试,您应该坚持使用 MockitoJUnitRunner。像这样的东西应该有效:
@RunWith(MockitoJUnitRunner.class)
public class MessagingControllerTest {
@Mock
private RabbitMessagingTemplate rabbitMessagingTemplate;
@InjectMocks
private MessagingController controller;
@Test
public void testPublishMessageConversionException() {
//given:
Message message = mock(Message.class);
//when:
when(rabbitMessagingTemplate.convertAndSend(anyObject()).thenThrow(new MessageConversionException());
try {
ResponseEntity<?> response = controller.publish(message);
fail();
} catch (MessageConversionException mce) {
//then:
assertThat(response).isNotNull();
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
verify(rabbitMessagingTemplate, times(1)).convertAndSend(message.getExchange(), message.getRoutingKey(), message.getPayload());
}
}
...
}
似乎那个模拟的 bean 没有被正确地存根。我必须使用特定的参数。 @Rozart还建议使用异常断言http://joel-costigliola.github.io/assertj/assertj-core-features-highlight.html#exception-assertion
这是工作中的:
@Test
public void testPublishMessageConversionException() {
//given:
Message message = new Message("", "", "");
//when:
doThrow(MessageConversionException.class).when(rabbitMessagingTemplate).convertAndSend("","","");
assertThatThrownBy(() -> { controller.publish(message); }).isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("Unable to convert payload");
}
基于Spring文档,MockBean不能被存根:https://docs.spring.io/spring-boot/docs/2.1.18.RELEASE/reference/html/boot-features-testing.html#boot-features -测试-spring-boot-applications-mocking-beans
@MockBean 不能用于模拟 bean 的行为 在应用程序上下文刷新期间执行。到考试的时候 执行后,应用程序上下文刷新已完成,也是 迟到配置模拟行为。我们建议使用@Bean 在这种情况下创建和配置模拟的方法。
作为解决方法,我们可以使用真实的 bean 创建一个
@TestConfiguration
,如果需要,在此配置中添加依赖的 @MockBean
-s:
@TestConfiguration
@Import({
MyService.class
})
public static class TestConfig {
....
}
之后,我们可以在测试类中注入一个
@SpyBean
- 间谍将监视@TestConfiguration
中配置的真实bean。现在我们可以使用间谍进行存根。
@SpyBean
private MyService myServiceSpy;
@Test
void myTest() {
doThrow(NullPointerException.class)
.when(myServiceSpy).myMethod(any());
}