如何在@WebMvcTest中的服务层上模拟自动装配的bean

时间:2019-09-17 06:17:43

标签: spring-boot testing mockito springmockito

我正在Spring Boot gradle应用程序中测试REST API,使用@MockBean的模拟服务返回null。如果服务类中有一些自动装配的bean,则此模拟服务将返回null(我使用构造函数注入)。

这里是示例代码(未编译,仅用于理解)


    @RestController
    @RequestMapping("/xxx")
    class TestController {

        private RetriveDataService retriveDataService;

        public TestControllerx(RetriveDataService retriveDataService) {
            this.retriveDataService = retriveDataService;
        }

        @PostMapping(value = "/yyy")
        public MyResponseModel myMethod(@RequestBody MyRequestModel model) {

            return retriveDataService.retriveData(model);
        }

    }

    @Service
    class RetriveDataService {

        private TokenService tokenService;

        public RetriveDataService(TokenService tokenService) {
            this.tokenService = tokenService;
        }

        public MyResponseModel retriveData(MyRequestModel model) {
            String accessToken = tokenService.getToken().getAccessToken();

            return retriveData(model, accessToken);
        }

    }

    @RunWith(SpringRunner.class)
    @WebMvcTest(TestController.class)
    public class TestControllerTest {

        @Autowired
        private MockMvc mvc;

        @Autowired
        private ObjectMapper objectMapper;

        @MockBean
        private RetriveDataService retriveDataService;

        @Test
        public void testRetriveData() throws Exception {

            mvc.perform(MockMvcRequestBuilders.post("/xxx/yyy").content(objectMapper.writeValueAsString(new MyRequestModel()))
                    .contentType(MediaType.APPLICATION_JSON_UTF8)).andDo(MockMvcResultHandlers.print())
                    .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));
        }

    }

运行此测试时,我得到以下输出(如果我的服务不需要另一个bean,则得到预期的输出)

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = []
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

由于此响应,我在.andExpect(content()。contentType(MediaType.APPLICATION_JSON_UTF8));上遇到问题。当我检查响应主体时(因为主体也是一个空值)

重现该问题的示例项目为here

1 个答案:

答案 0 :(得分:0)

检查存储库中已确认的假设,形成问题讨论中的讨论。

您指定对模拟的期望

MyModel requestMessage = new MyModel();
requestMessage.setMessage("Hello Request Post");
given(testService1.getMessage(requestMessage)).willReturn(responseMessage);

,但是在@WebMvcTest中的控制器中接收到的消息不等于测试中指定的requestMessage。这是因为MyModel类没有覆盖equals方法。 在这种情况下,Mockito将使用其默认行为:

  

默认情况下,对于所有返回值的方法,模拟将酌情返回null,原始/原始包装器值或空集合。例如,对于int / Integer为0,对于boolean / Boolean为false。

您有两种方法可以解决此问题:

  1. 在请求类中覆盖equals(和hashCode)。
  2. 结识参数匹配器

有关选项2的更多信息:

从技术上讲,您的期望等同于:

given(testService1.getMessage(ArgumentMatchers.eq(requestMessage)))
  .willReturn(responseMessage);

您可以使用其他匹配器,甚至可以定义自己的匹配器。如果您无法修改自变量类型的代码(类型来自3方库等),这将很有用。 例如,您可以使用ArgumentMatchers.any(MyModel.class))