Spring-如何使用ApplicationEventPublisher依赖项测试Controller?

时间:2018-08-30 12:20:15

标签: spring spring-boot testing event-handling

我有一个发布事件的控制器

@RestController
public class Controller
{
    @Autowired
    private ApplicationEventPublisher publisher;

    @GetMapping("/event")
    public void get()
    {
        publisher.publishEvent(new Event());
    }
}

现在,我想测试事件是否已发布。首先,我尝试@MockBean ApplicationEventPublisher并验证方法调用。但这根据https://jira.spring.io/browse/SPR-14335

不起作用

所以我是这样做的:

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = Controller.class)
public class ControllerTest
{
    @Autowired
    private MockMvc mockMvc;

    @Test
    public void getTest() throws Exception
    {
        this.mockMvc.perform(get("/").contentType(MediaType.APPLICATION_JSON)
                    .andExpect(status().isOk());
        assertNotNull(Listener.event);
    }

    @TestConfiguration
    static class Listener
    {
        public static Event event;

        @EventListener
        void listen ( Event incoming )
        {
            event = incoming;
        }
    }
}

这种常见用例是否有更简单的方法?

2 个答案:

答案 0 :(得分:2)

您可以这样做

@RunWith(SpringRunner.class)
public class ControllerTest {

    private MockMvc mockMvc;

    @MockBean
    private ApplicationEventPublisher publisher;

    @Before
    public void setup() {
        Controller someController= new Controller(publisher);
        mockMvc = MockMvcBuilders.standaloneSetup(someController).build();
    }

    @Test
    public void getTest() throws Exception
    {
        ArgumentCaptor<Event> argumentCaptor = ArgumentCaptor.forClass(Event.class);
        doAnswer(invocation -> {
            Event value = argumentCaptor.getValue();
             //assert if event is correct
            return null;
        }).when(publisher).publishEvent(argumentCaptor.capture());  

        this.mockMvc.perform(get("/").contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk());

        verify(publisher, times(1)).publishEvent(any(Event.class));
    }

}  

并在您的控制器类中将“字段注入”更改为“构造函数注入”(这是一个好习惯)。

@RestController
public class Controller
{

  private ApplicationEventPublisher publisher;

  @Autowired
  public Controller(ApplicationEventPublisher publisher) {
      this.publisher = publisher;
  }
 ....
}

答案 1 :(得分:0)

我面临同样的问题,现在我使用 TestConfiguration 解决了这个问题:

@SpringBootTest
class MyUseCaseIT {

  @Autowired private ApplicationEventPublisher publisher;
  @Autowired private MyService service;

@Test
  void callUseCase() {
var event = mock(MyEvent.class);
    doNothing().when(publisher).publishEvent(event);

service.useCase();

    verify(publisher).publishEvent(event);
}


@TestConfiguration
  static class MockitoPublisherConfiguration {

    @Bean
    @Primary
    ApplicationEventPublisher publisher() {
      return mock(ApplicationEventPublisher.class);
    }
  }