Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring-如何使用ApplicationEventPublisher依赖项测试控制器?_Spring_Spring Boot_Testing_Event Handling - Fatal编程技术网

Spring-如何使用ApplicationEventPublisher依赖项测试控制器?

Spring-如何使用ApplicationEventPublisher依赖项测试控制器?,spring,spring-boot,testing,event-handling,Spring,Spring Boot,Testing,Event Handling,我有一个正在发布事件的控制器 @RestController public class Controller { @Autowired private ApplicationEventPublisher publisher; @GetMapping("/event") public void get() { publisher.publishEvent(new Event()); } } 现在我想测试事件是否已发布。首先,我尝试

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

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

    @GetMapping("/event")
    public void get()
    {
        publisher.publishEvent(new Event());
    }
}
现在我想测试事件是否已发布。首先,我尝试使用ApplicationEventPublisher@MockBean并验证方法调用。但这并不能根据实际情况发挥作用

所以我是这样做的:

@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;
        }
    }
}

对于这个常用用例,有没有更简单的方法?

您可以这样做

@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));
    }

}  

另一种可能性是在测试中使用反射将控制器上的ApplicationEventPublisher实例替换为模拟实例:

public class ControllerTest {
...
    // Collect your controller
    @Autowired
    private Controller controller;

    // Use the mock publisher
    @MockBean
    private ApplicationEventPublisher publisherMock;

    // E.g. in setup set the mock publisher on your controller
    @Before
    public void setup() {
        ReflectionTestUtils.setField(controller, "publisher", publisherMock);
    }
...

这是一个非常好的方法。我不知道:
mockMvc=MockMvcBuilders.standaloneSetup(someController.build()只是这一部分有点烦人:
@SpringBootTest
中的
classes=MockServletContext.class
。是否没有内置注释来启用此行为?@davidxxx实际上根本不需要它。即使没有它,它也能工作。编辑了我的回答,这样更好。好吧,关键是手动将模拟发布者注入控制器。所以您不需要MockBean,只需要Mock annotation.ya,
@Mock
就足够了。我们必须这样做,因为你已经提到的错误
public class ControllerTest {
...
    // Collect your controller
    @Autowired
    private Controller controller;

    // Use the mock publisher
    @MockBean
    private ApplicationEventPublisher publisherMock;

    // E.g. in setup set the mock publisher on your controller
    @Before
    public void setup() {
        ReflectionTestUtils.setField(controller, "publisher", publisherMock);
    }
...