[MockBean在使用MockMvc standaloneSetup时未初始化服务bean

问题描述 投票:0回答:1

这里我使用WebMvcTestMockMvc测试我的端点,并使用@MockBean测试模拟服务。在不使用standaloneSetup方法的情况下,以下代码可以正常运行。

public class MessageControllerTest {

    @Nested
    @WebMvcTest
    class TestUsingMockServer {

        @MockBean
        MessageServiceImpl messageService;

        @Autowired
        MockMvc mockMvc;

        @Test
        public void test_to_return_id_with_message_json() throws Exception {

            when(messageService.findById(anyLong())).thenAnswer(invocation -> new Message("Hello World", (Long) invocation.getArguments()[0], LocalDateTime.now()));

            mockMvc.perform(get("/resources/messages/{id}", 3)
                                    .contextPath("/resources")
                                    .accept(MediaType.APPLICATION_JSON))
                    .andDo(print())
                    .andExpect(content().contentType(MediaType.APPLICATION_JSON))
                    .andExpect(status().isOk())
                    .andExpect(result -> {
                        result.toString().contains("3");
                        result.toString().contains("Hello World");
                    });

        }


        @Test
        public void test_to_get_the_name_passed() throws Exception {

            when(messageService.getMessageByIdName(anyLong(), anyString())).thenAnswer(invocation -> new Message("Hello " + invocation.getArguments()[1],
                    (Long) invocation.getArguments()[0], LocalDateTime.now()));


            mockMvc.perform(get("/resources/messages/{id}", 3)
                                    .queryParam("name", "kaustubh")
                                    .contextPath("/resources")
                                    .accept(MediaType.APPLICATION_JSON))
                    .andDo(print())
                    .andExpect(content().contentType(MediaType.APPLICATION_JSON))
                    .andExpect(status().isOk())
                    .andExpect(result -> {
                        result.toString().contains("3");
                        result.toString().contains("kaustubh");
                    });

        }

    }
}

为了避免重复,当我添加standaloneSetup方法并运行测试时,我得到一条错误消息,提示MessageServiceImpl bean未初始化(由于[C​​0])

NullPointerException

出现以下错误

public class MessageControllerTest { @Nested @WebMvcTest class TestUsingMockServer { @MockBean MessageServiceImpl messageService; @Autowired MockMvc mockMvc; @BeforeEach public void setUp(){ mockMvc = standaloneSetup(new MessageController()) .defaultRequest(get("/") .contextPath("/resources") .accept(MediaType.APPLICATION_JSON) ).build(); } @Test public void test_to_return_id_with_message_json() throws Exception { when(messageService.findById(anyLong())).thenAnswer(invocation -> new Message("Hello World", (Long) invocation.getArguments()[0], LocalDateTime.now())); mockMvc.perform(get("/resources/messages/{id}",3)) .andDo(print()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(result -> { result.toString().contains("3"); result.toString().contains("Hello World"); }); } } }

第17行如所指,在错误中,调用MessageServiceImpl

Error showing NullPointerException in MessageController

发生是因为@RestController @RequestMapping("/messages") public class MessageController { @Autowired MessageServiceImpl messageService; @GetMapping(path = "/{id}") public Message getMessageById(@PathVariable Long id) { return messageService.findById(id); // LINE 17 } @GetMapping(path = "/{id}", params = "name") public Message getMessageByIdName(@PathVariable Long id, @RequestParam(value = "name", defaultValue = "ST") String name) { return messageService.getMessageByIdName(id, name); } } 构建器是在创建服务bean之前设置的?

java spring-boot spring-mvc junit5 mockmvc
1个回答
0
投票

关于测试设置,您需要了解几件事。

在您的第一个示例中:

MockMvc

这里测试上下文由@WebMvcTest启动,因此可以自动装配MockMvc。 @WebMvcTest还将查看@Mockbean来查看需要模拟的内容。

在第二个示例中:

@WebMvcTest
class TestUsingMockServer {

    @MockBean
    MessageServiceImpl messageService;

    @Autowired
    MockMvc mockMvc;

这里您正在用另一个实例覆盖@Autowired mockMvc对象。在这里,您将设置上下文,

    @WebMvcTest
    class TestUsingMockServer {

        @MockBean
        MessageServiceImpl messageService;

        @Autowired
        MockMvc mockMvc;

        @BeforeEach
        public void setUp(){
            mockMvc = standaloneSetup(new MessageController())
                              .defaultRequest(get("/")
                                                      .contextPath("/resources")
                                                      .accept(MediaType.APPLICATION_JSON)
                              ).build();
        }

此设置将跳过任何自动装配,因此在您的MessageController类中,

        mockMvc = standaloneSetup(new MessageController())

将被跳过。并且将为null。

因此寻求解决方案。一个简单的解决方法是按构造函数进行自动装配:

@Autowired
MessageServiceImpl messageService;

现在,您只需在测试类中添加您的模拟:

@Autowired
public MessageController(MessageServiceImpl messageService) {
 this.messageService = messageService;
}

这将解决您的问题。

[我要提供的其他建议是,您不必担心重复测试。一旦加载了上下文,它们将运行得非常快。

© www.soinside.com 2019 - 2024. All rights reserved.