Spring Boot:如何编写用于删除RestTemplate的单元测试案例

huangapple go评论65阅读模式
英文:

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

问题

以下是您提供的内容的翻译部分:

我正在尝试为 HttpHandler 类编写单元测试用例,该类在其中调用了删除的 rest template 调用。我已经创建了一个 usercontroller 类,以便在其中进行 resttemplate 调用,以测试 HttpHandler 类中 sendDelete 方法的功能。有人可以帮助我理解如何正确编写 HtttpHandler 类中 sendDelete 方法的单元测试用例吗?

我有一个名为 HttpHandler 的类。它有一个名为 sendDelete 的函数,在其中调用了 resttemplate.exchange 方法。

@Service
public class HttpHandler {
    public <T, R> ResponseEntity<Void> sendDelete(String url, HttpHeaders httpHeaders, R requestBody, Class<T> responseClass) {
        // 创建 rest template 实例
        RestTemplate restTemplate = new RestTemplate();
        HttpEntity<R> entity = new HttpEntity<R>(requestBody, httpHeaders);
        logger.info("DELETE 请求至 " + url + ",使用 body: " + JsonUtil.jsonizeExcludeNulls(requestBody));
        // 使用 headers 发起 HTTP DELETE 请求
        ResponseEntity<Void> response = restTemplate.exchange(url, HttpMethod.DELETE, entity, Void.class);
        logger.info("DELETE " + url + ":" + JsonUtil.jsonize(response));
        return response;
    }
}

我正在使用 JUnit 5。以下是上述类中 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";
    // 创建 headers
    HttpHeaders httpHeaders = new HttpHeaders();

    // 设置内容类型
    httpHeaders.setContentType(MediaType.APPLICATION_JSON);
    httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

    // 使用 headers 发起 HTTP DELETE 请求
    ResponseEntity<Void> actual = httpHandler.sendDelete(baseUrl, httpHeaders, null, Void.class);
    assertEquals(404, actual.getStatusCodeValue());
}

以下是用户控制器类:

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

谢谢您的时间!

英文:

I'm trying to write unit test case for HttpHandler class which has rest template call for delete. I've crated a usercontroller class to make resttemplate call in order to test the functionality of sendDelete in HttpHandler class. Can someone help me too understand what is the correct way to write unit test case for sendDelete method in HtttpHandler class?

I have a class HttpHandler. It has a function sendDelete where it calls resttemplate.exchange method

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

I'm using junit5. Below is the unit test case for sendDelete method in above class:

@LocalServerPort
    private int port;

    private String baseUrl;

    @Autowired
    private HttpHandler httpHandler;

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

@Test
    public void testSuccessDeleteUserById() throws Exception{
        this.baseUrl = baseUrl + &quot;/1&quot;;
        //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&lt;Void&gt; actual = httpHandler.sendDelete(baseUrl, httpHeaders, null, Void.class);
        assertEquals(404, actual.getStatusCodeValue());
    }

Below is the user controller class

@RestController
public class UserController {
@DeleteMapping(&quot;/users/{userId}&quot;)
    public ResponseEntity&lt;Void&gt; deleteUser(@PathVariable(&quot;userId&quot;) int userId){
        return new ResponseEntity&lt;Void&gt;(HttpStatus.NOT_FOUND);
    }
}

Thank you for your time!

答案1

得分: 0

以下是翻译好的部分:

  1. Mocking RestTemplate. 要做到这一点,首先,您必须将 RestTemplate 设置为一个字段,并通过构造函数(或任何其他方式)注入它。这允许您注入一个模拟对象。然后,其余部分就是简单的模拟。

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

}

// 仅供使用作为有效载荷的示例类
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。如果这样做,第一种解决方案将不再起作用,而第二种解决方案将保持不变。

英文:

There are two ways to do it.

  1. Mocking RestTemplate. To do it, first, you have to make the RestTemplate a field, and inject it through the constructor (or any other way). This allows you to inject a mock object. Then, the rest is plain and simple mocking.

  2. You can use MockWebServer. This way you do not need to change anything. It is just a web server that your method will send the request to. After the method call finishes, you can access the recorded request and make some validations.

Here's a crude example. If you will have a lot of those tests, then you can move the web server initialization to a @BeforeEach method and the destroying to @AfterEach method.

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 = &quot;http://localhost:9889&quot;;
        Hello hello = new Hello(&quot;hello world&quot;);

        final ResponseEntity&lt;Void&gt; entity = handler.sendDelete(url, null, hello, Hello.class);

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

        final RecordedRequest recordedRequest = mockWebServer.takeRequest();

        assertEquals(&quot;DELETE&quot;, 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;
    }
}

Note. Even though you will not opt for the first solution, I recommend you do abandon initializing RestTemplate for each request. You better use WebClient instead. If you do so, the first solution will not work anymore, while the second will remain intact.

huangapple
  • 本文由 发表于 2020年8月1日 11:28:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/63201464.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定