Spring Boot:如何为删除其余模板编写单元测试用例

Posted

技术标签:

【中文标题】Spring Boot:如何为删除其余模板编写单元测试用例【英文标题】:Spring boot : How to write unit test case for delete rest template 【发布时间】:2020-11-21 20:51:14 【问题描述】:

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

我有一个类 HttpHandler。它有一个函数sendDelete,它调用resttemplate.exchange method

@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。下面是上面类中 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());
    

下面是用户控制器类

@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。

    您可以使用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 。如果这样做,第一个解决方案将不再有效,而第二个解决方案将保持不变。

【讨论】:

感谢您的宝贵时间和所有帮助。 @ 987654325@ 请您帮我理解这示例的确切含义。再次感谢! 基本上,每次发出请求时不要初始化RestTemplate。把它变成一个 bean 并注入到你的类中。 好的,谢谢!!可以在每个请求上初始化 HttpHeaders 吗?我应该创建一个 bean 并注入它吗? 标头特定于请求,所以不,您不需要这样做。 好的,谢谢你分享mockWebServer。我不知道。

以上是关于Spring Boot:如何为删除其余模板编写单元测试用例的主要内容,如果未能解决你的问题,请参考以下文章

如何为我的 Spring Boot 控制器执行单元测试?

如何为速度模板编写单元测试?

使用 Spring Security 进行 Spring Boot 单元测试

如何为具有属性依赖项的 Spring Boot Application 类编写测试用例 - 无法解析占位符

如何为@KafkaListener 编写单元测试?

用于 RowMapper 的 Spring jdbc 模板的单元测试用例