【问题标题】:How to make a simple rest api controller test?如何做一个简单的rest api控制器测试?
【发布时间】:2021-08-06 15:46:59
【问题描述】:

所以我正在尝试对我的控制器的 post 方法进行测试,但我不断发现其他人的测试不能使用我的或他们的 post 方法更高级。

我的发帖方式

@Autowired
PartyLeaderService partyleaderService;

@PostMapping("/")
public void add(@RequestBody PartyLeaderDto partyLeaderDto){
    partyLeaderService.savePartyLeader(partyLeaderDto);
}

如您所见,它相当简单,但我似乎仍然无法让它正常工作。 我试过这个方法:

@Test
public void testPostExample() {
    PartyLeaderDto partyLeaderDto = new PartyLeaderDto(1, "arun", "link");

    partyLeaderController.add(partyLeaderDto);
    Mockito.verify(partyLeaderController).add(partyLeaderDto);
}

但是SonarQube说这个方法还没有被测试覆盖,所以我的测试肯定是错的。

我的 DTO

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Builder
public class PartyLeaderDto {
    private Integer id;
    private String name;
    private String apperance;
}

任何人都可以帮助我,因为我认为答案很简单,但我似乎找不到它。

【问题讨论】:

    标签: java spring-boot unit-testing controller spring-test


    【解决方案1】:

    你的单元测试的问题是你正在验证一个不是模拟的调用

    Mockito.verify(partyLeaderController).add(partyLeaderDto);
    

    partyLeaderController 不是一个模拟,因为这是您目前要测试的。 你应该模拟和验证的是PartyService

      @Test
      public void testPostExample() {
        PartyService partyService = mock(PartyService.class);
        PartyLeaderController controller = new PartyLeaderController(partyService);
        PartyLeaderDto partyLeaderDto = new PartyLeaderDto(1, "arun", "link");
    
        controller.add(partyLeaderDto);
        
        Mockito.verify(partyService).saveParty(partyLeaderDto);
      }
    

    但是,这不是一个测试 Web 层的好方法,因为您应该在测试中涵盖的内容不仅是是否调用了 PartyService,而且还要在给定路径中公开端点,这个端点期待 POST 方法,它期待一个对象(也许是 json?)并且它正在返回一个状态代码(也许是一个响应对象?)

    一个简单的、类似单元测试的方法是使用 MockMvc。

      @Test
      public void testPostExample() {
        PartyService partyService = mock(PartyService.class);
        MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new PartyLeaderController(partyService)).build();
        PartyLeaderDto partyLeaderDto = new PartyLeaderDto(1, "arun", "link");
    
        mockMvc.perform(
            post("/party")
                .contentType(MediaType.APPLICATION_JSON)
                .content(new ObjectMapper().writeValueAsString(partyLeaderDto))
        ).andExpect(status().isOk());
        verify(partyService).saveParty(partyLeaderDto);
      }
    

    【讨论】:

    • 我在这一行收到以下错误: MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new PartyLeaderController(partyService)) Expected 0 arguments but found 1 我的控制器没有构造函数。我应该用其中的服务制作一个吗?
    • 当我编辑该行时: MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new PartyLeaderController());我收到以下错误:必需类型:MockMvc 提供:StandaloneMockMvcBuilder
    • 是的,建议使用构造函数注入与字段级注入,这样做的主要好处之一是更容易测试:) 这里有一些关于它的参考stackoverflow.com/questions/40737720/…
    • 糟糕,最后我忘记了 .build(),将编辑我的答案。
    • 现在这是我得到的下一个错误:想要但未调用:partyLeaderService.savePartyLeader(com.example.demo.DTO.PartyLeaderDto@3136e15a); -> at com.example.demo.Controller.PartyLeaderEndpointTests.testPostExample(PartyLeaderEndpointTests.java:97) 实际上,与此模拟的交互为零。
    【解决方案2】:

    您在这里所做的实际上是通过验证存根调用进行的单元测试。

    您可以通过使用 Mockito 的 when(....).then(...) 模拟行为,然后使用断言来断言结果来进行单元测试。

    或 您可以按照这篇文章一步一步地使用 MockMvc 进行集成测试 - https://www.baeldung.com/integration-testing-in-spring

    【讨论】:

      【解决方案3】:

      在 Yayotron 的帮助下,我得到了答案。 这是代码:

      @Test
      @WithMockUser("Test User")
      public void testPostParty() throws Exception {
          PartyLeaderService partyLeaderService = mock(PartyLeaderService.class);
          MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new PartyLeaderController(partyLeaderService)).build();
          PartyLeaderDto partyLeaderDto = new PartyLeaderDto(1, "arun", "link");
      
          mockMvc.perform(
                  MockMvcRequestBuilders.post("http://localhost:8080/partyleaders/")
                          .contentType(MediaType.APPLICATION_JSON)
                          .content(new ObjectMapper().writeValueAsString(partyLeaderDto))
          ).andExpect(status().isOk());
          Mockito.verify(partyLeaderService).savePartyLeader(ArgumentMatchers.refEq(partyLeaderDto));
      }
      

      非常感谢您的帮助!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-08
        • 2012-05-25
        • 1970-01-01
        • 2023-03-09
        • 2019-04-18
        • 1970-01-01
        相关资源
        最近更新 更多