Java 如何进行简单的RESTAPI控制器测试?

Java 如何进行简单的RESTAPI控制器测试?,java,spring-boot,unit-testing,controller,spring-test,Java,Spring Boot,Unit Testing,Controller,Spring Test,因此,我试图对我的控制器的post方法进行测试,但我不断发现,其他人对我或他们的post方法不进行操作的测试要高级得多 我的发帖方法 @Autowired PartyLeaderService partyleaderService; @PostMapping("/") public void add(@RequestBody PartyLeaderDto partyLeaderDto){ partyLeaderService.savePartyLeader(part

因此,我试图对我的控制器的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;
}

有人能帮我吗,因为我认为答案相当简单,但我似乎找不到它。

单元测试的问题是,您正在验证对非模拟对象的调用

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

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

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

或 您可以按照本文使用MockMvc一步一步地进行集成测试-

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

非常感谢你的帮助

我在此行中遇到以下错误:MockMvc MockMvc=MockMvcBuilders.StandaloneStup(新PartyLeaderController(partyService))应为0个参数,但发现1我的控制器没有构造函数。我应该在其中创建一个服务吗?同样,当我将该行编辑为以下内容时:MockMvc MockMvc=MockMvcBuilders.standaloneSetup(新PartyLeaderController());我得到了以下错误:必需类型:MockMvc提供:StandaloneMockMVCBuilderies,建议使用构造函数注入与字段级注入,其中一个关键好处是更容易测试:)下面是一些关于它的参考资料Oops,我最后忘了.build(),将编辑我的答案。现在这是我得到的下一个错误:需要但未调用:partyLeaderService.savePartyLeader(com.example.demo.DTO)。PartyLeaderDto@3136e15a ); -> 实际上,在com.example.demo.Controller.PartyLeaderEndpointTests.testPostExample(PartyLeaderEndpointTests.java:97)上,与此模拟的交互为零。