Spring boot : 如何编写用于删除 rest 模板的单元测试用例

Spring boot : How to write unit test case for delete rest template

我正在尝试为 HttpHandler class 编写单元测试用例,它具有用于删除的其余模板调用。为了测试 HttpHandler class 中 sendDelete 的功能,我创建了一个用户控制器 class 来进行 resttemplate 调用。有人可以帮我理解在 HtttpHandler class 中为 sendDelete 方法编写单元测试用例的正确方法是什么?

我有一个 class HttpHandler。它有一个函数 sendDelete 调用 resttemplate.exchange 方法

@Service
public class HttpHandler {
public <T,R> ResponseEntity<Void> sendDelete(String url, HttpHeaders httpHeaders, R requestBody, Class<T> responseClass) {
        //create an instance of rest template
        RestTemplate restTemplate = new RestTemplate();
        HttpEntity<R> entity = new HttpEntity<R>(requestBody, httpHeaders);
        logger.info("DELETE request to " + url + " with body: " + JsonUtil.jsonizeExcludeNulls(requestBody));
        //make an HTTP DELETE request with headers
        ResponseEntity<Void> response = restTemplate.exchange(url, HttpMethod.DELETE, entity, Void.class);
        logger.info("DELETE" + url + ": " + JsonUtil.jsonize(response));
        return response;
    }
}

我正在使用 junit5。下面是上面class:

中sendDelete方法的单元测试用例
@LocalServerPort
    private int port;

    private String baseUrl;

    @Autowired
    private HttpHandler httpHandler;

    @BeforeEach
    public void setBaseUrl(){
        this.baseUrl = "http://localhost:"+ port + "/users";
    }

@Test
    public void testSuccessDeleteUserById() throws Exception{
        this.baseUrl = baseUrl + "/1";
        //create headers
        HttpHeaders httpHeaders = new HttpHeaders();

        //set content type
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

        //make an HTTP DELETE request with headers

        ResponseEntity<Void> actual = httpHandler.sendDelete(baseUrl, httpHeaders, null, Void.class);
        assertEquals(404, actual.getStatusCodeValue());
    }

下面是用户控制器class

@RestController
public class UserController {
@DeleteMapping("/users/{userId}")
    public ResponseEntity<Void> deleteUser(@PathVariable("userId") int userId){
        return new ResponseEntity<Void>(HttpStatus.NOT_FOUND);
    }
}

感谢您的宝贵时间!

有两种方法。

  1. 模拟 RestTemplate。为此,首先,您必须使 RestTemplate 成为一个字段,并通过构造函数(或任何其他方式)注入它。这允许您注入模拟对象。然后,剩下的就是简单明了的mocking了。

  2. 可以使用MockWebServer。这样你就不需要改变任何东西。它只是一个 Web 服务器,您的方法将向其发送请求。方法调用完成后,您可以访问记录的请求并进行一些验证。

这是一个粗略的例子。如果你有很多这样的测试,那么你可以将 Web 服务器初始化移动到 @BeforeEach 方法,并将销毁移动到 @AfterEach 方法。

public class HttpHandlerTest {

    private final HttpHandler handler = new HttpHandler();

    @Test
    @SneakyThrows
    public void testDelete() {
        MockWebServer mockWebServer = new MockWebServer();
        mockWebServer.start(9889);

        mockWebServer.enqueue(
                new MockResponse().setResponseCode(200)
        );

        String url = "http://localhost:9889";
        Hello hello = new Hello("hello world");

        final ResponseEntity<Void> entity = handler.sendDelete(url, null, hello, Hello.class);

        assertNotNull(entity);
        assertEquals(200, entity.getStatusCode().value());

        final RecordedRequest recordedRequest = mockWebServer.takeRequest();

        assertEquals("DELETE", recordedRequest.getMethod());
        
        mockWebServer.close();
    }

}

// just an example class to use as a payload
class Hello {
    String text;

    public Hello() {
    }

    public Hello(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

注意。即使您不会选择第一种解决方案,我还是建议您放弃为每个请求初始化 RestTemplate。您最好改用 WebClient。如果这样做,第一个解决方案将不再有效,而第二个将保持不变。