单元测试 MockHttpServletRequest 不返回内容类型

2024-01-13

我希望应用程序从我的 Java 类返回 JSON 对象(成功和失败情况)。

我定义了一个@RestControllerAdvice处理来自控制器的错误。我的程序也在json中正确显示错误消息,但问题出在单元测试.

问题是当它抛出时:

org.springframework.web.bind.MethodArgumentNotValidException

我的单元测试失败并出现错误:

java.lang.AssertionError: Response header 'content-type' expected:<application/json;charset=UTF-8> but was:<null>

控制器:

@PostMapping("/import")
public ResponseEntity<StatusModel> import(@Valid @RequestBody ImportModel importModel ){
    //logic
    return new ResponseEntity<>(new StatusModel("Data accepted."), HttpStatus.OK);

}

单元测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MockConfiguration.class})
@WebAppConfiguration
public class ModelControllerTest {

    private MockMvc mockMvc;

    @InjectMocks
    private ModelController controller;

    @Before
    public void setUp() {
        mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
    }

    @Test
    public void import_validRequest_imported() throws Exception {

        mockMvc
            .perform(
                post("/import")
                    .content(VALID_CONTENT).contentType("application/json;charset=UTF-8"))
            .andExpect(status().isOk())
            .andExpect(header().string("content-type", "application/json;charset=UTF-8"))
            .andExpect(jsonPath("$.status", equalTo("Data accepted")));
    }

    @Test
    public void import_invalidRequest_notImported() throws Exception {    
        mockMvc
            .perform(
                post("/import")
                    .content(INVALID_CONTENT).contentType("application/json"))
            .andExpect(status().isBadRequest())
            .andDo(print())
            .andExpect(header().string("content-type", "application/json"));  <----- This assertion failed
    }   
}

MockHttpServletRequest 日志:

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /import
       Parameters = {}
          Headers = {Content-Type=[application/json]}

Handler:
             Type = com.test.ModelController
           Method = public org.springframework.http.ResponseEntity<com.model.StatusModel> com.ModelController.import(com.test.model.ImportModel)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = org.springframework.web.bind.MethodArgumentNotValidException

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 400
    Error message = null
          Headers = {}
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

为什么内容类型是空的,错误信息是空的?


以下是mock mvc不支持spring boot异常处理程序的原因,然后是建议和修复。

理性摘录

Spring Boot的错误处理是基于Servlet容器错误 导致 ERROR 分派到 ErrorController 的映射。 然而,MockMvc 是无容器测试,因此没有 Servlet 容器 异常只是冒泡而没有任何东西可以阻止它。

因此 MockMvc 测试根本不足以测试错误响应 通过 Spring Boot 生成。我认为你不应该 测试 Spring Boot 的错误处理。如果您要自定义它 您可以编写 Spring Boot 集成测试的方式(使用实际的 容器)来验证错误响应。然后针对 MockMvc 测试重点 全面测试 Web 层,同时期待出现异常 向上。

这是典型的单元测试与集成测试的权衡。你做单位 即使他们没有测试所有内容,也要进行测试,因为它们会为您提供更多 控制并跑得更快。

推荐摘录

我们如何使用默认的 spring-boot 编写错误条件测试 那么 JSON 响应呢?

@xak2000 罗森已经介绍过这一点,但我想给你一个 直接回答。如果你真的想测试的精确格式 错误响应,那么您可以使用集成测试 @SpringBootTest 配置了 DEFINED_PORT 或 RANDOM_PORT web 环境和 TestRestTemplate。

完整详细信息请参见此处https://github.com/spring-projects/spring-boot/issues/7321 https://github.com/spring-projects/spring-boot/issues/7321

Fix

这里是使用 Spring Boot 测试的稍微不同的错误验证。

import org.json.JSONException;
import org.junit.jupiter.api.Test;
import org.skyscreamer.jsonassert.JSONAssert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.*;
import static org.junit.jupiter.api.Assertions.assertEquals;

@SpringBootTest(classes = DemoApplication.class,
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ModelControllerTest {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    void import_invalidRequest_notImported() throws JSONException {

        String expected = "{\"status\":400,\"error\":\"Bad Request\",\"message\":\"JSON parse error: Unrecognized token 'Invalid': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false'); nested exception is com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'Invalid': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')\\n at [Source: (PushbackInputStream); line: 1, column: 8]\",\"path\":\"/import\"}";

        String invalidJson = "Invalid";

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<>(invalidJson, headers);

        ResponseEntity<String> response = restTemplate.exchange("/import", HttpMethod.POST, entity, String.class);

        assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
        assertEquals(MediaType.APPLICATION_JSON, response.getHeaders().getContentType());
        JSONAssert.assertEquals(expected, response.getBody(), false);

    }

}

参考这里https://mkyong.com/spring-boot/spring-rest-integration-test-example/ https://mkyong.com/spring-boot/spring-rest-integration-test-example/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

单元测试 MockHttpServletRequest 不返回内容类型 的相关文章

随机推荐

  • R:如何在数据帧内进行偏移和匹配?

    我想使用类似于Excel的OFFSET和MATCH函数的东西 这里是一个示例数据集 数据 Which Test Test1 Test2 Test3 RESULT Test1 TRUE 80 0 Test2 FALSE 25 0 Test1
  • Java继承中的“this”关键字如何工作?

    在下面的代码片段中 结果确实令人困惑 public class TestInheritance public static void main String args new Son Father father new Son System
  • 事件的 Google Analytics 屏幕名称

    我对 Google Analytics 中的 屏幕名称 维度感到困惑 如果您转到 行为 gt 事件 gt 屏幕 您就会看到它 我想知道如何将屏幕名称附加到事件中 目前我正在跟踪屏幕浏览 点击 和事件 点击 我认为分析可以通过查看最后一个屏幕
  • 从 MySQL 中的表的一部分中选择最小值和最大值

    如果我想从整个表中选择最小值和最大值 我可以使用 SELECT min price as min price max price as max price FROM prices 但是如何从表的一部分中选择最小值和最大值呢 例如 我的表中有
  • 经典asp和ASP.NET之间的密码加密/解密

    我有 2 个网站 一个用经典 ASP 编写 另一个用 ASP NET 1 1 框架 编写 这两个应用程序都使用登录机制来验证基于共享数据库表的用户凭据 到目前为止 密码存储在单向 MD5 哈希中 这意味着如果人们丢失旧密码 则必须为其提供新
  • 用于计算百分位数的条件数组

    我有一些数据如下 val crit perc 0 415605498 1 perc1 0 475426007 1 perc1 0 418621318 1 perc1 0 51608229 1 perc1 0 452307882 1 perc
  • iOS VoiceOver 崩溃(消息发送到已释放的实例)

    在启用 VoiceOver 的情况下运行我的应用程序时 我遇到了奇怪的崩溃 该应用程序有一个侧边栏界面 如 Facebook 当点击其中之一时UITableViewCells 在侧边栏中UITableView 我换出视图控制器 根据点击的单
  • 如何设置 JMenuItem 的大小?

    正如你所看到的 拥有这些东西是很丑陋的JMenuItem是 菜单项的宽度非常小 这是代码 JMenu menuOne new JMenu MenuOne JMenu menuTwo new JMenu MenuTwo JMenu menuT
  • 如何使用 pytest 装置和 django 在unittest中创建类似于“setUp”的方法

    我的测试文件中有下面的代码并尝试重构它 我是 pytest 的新手 我正在尝试实现与 unittest 可用的类似方法 setUp 以便能够将数据库中创建的对象检索到其他函数 而不是重复代码 在这种情况下我想重用month from 测试设
  • @ManyToOne 和 @OneToOne 与 @EmbeddedId 的关系

    我正在尝试将数据库实体的 id 从单个 long 更改为由两个 long 组成的复合 id 这两个 long 封装在我的 ID class 中 如下所示 您会为 ManyToOne 和 OneToMany 关系使用什么注释 我的注释是否有错
  • Capistrano 3:在任务中使用服务器自定义变量

    我有多阶段多服务器设置 在我的任务中我需要使用服务器名称 例如在 stagin rb 我有 set stage staging Define servers server xxx xx xx xxx user deploy roles w
  • 使用Automapper时如何忽略特定类型的属性?

    假设我有两种类型 class Type1 public int Prop1 get set public string Prop2 get set public string Prop3 get set class Type2 public
  • SwiftUI:当 List 和 ForEach 嵌入 TabView 时,WatchOS 8.1 中的 NavigationView 错误

    下面的代码在 WatchOS 7 和 8 0 中运行良好 但现在在 8 1 中 点击该行将导航到目的地 但随后立即导航回根视图 我提交了反馈 FB9727188 并包含以下内容来演示该问题 struct ContentView View S
  • 如何访问 SwiftUI 中的子视图?

    我正在开发 SwiftUI 感觉它与 React 非常相似 刚才我正在自定义一个SwiftUI的Button 遇到一个问题 无法动态访问Button的子视图 以下代码是我要做的 struct FullButton View var acti
  • javascript 原型和闭包中的“this”访问

    我是js初学者 对下面的代码感到困惑 Foo function arg this arg arg Foo prototype init function var f function alert current arg this arg a
  • 添加一个点来扩展多边形而不将其附加到 Google 地图中?

    我正在通过标记在 Google 地图中构建一个多边形 可以拖动这些标记来重塑它的形状 因此 当有 3 个标记时 将绘制多边形 并在形状中附加更多标记 将其扩展 当用户只想遵循简单的顺时针 逆时针模式时 这很好 但是当他想要通过其边缘之一扩展
  • 显示播客列表中的剧集列表

    我正在尝试显示特定作者的播客频道列表 选择播客后 显示相关剧集 我能够独立完成每一项工作 但不知道如何将两者联系起来 现在我的作者播客列表是使用以下命令生成的iTunes 应用商店搜索 API http www apple com itun
  • 用于在输入点和数字后禁止输入点的正则表达式 JavaFX

    我需要输入用逗号分隔的连续整数和实数 如下所示 2 12 4 3 我禁止通过以下表达式连续输入两个逗号 两个点和除数字之外的所有其他字符 2 d 但有了它我可以输入 2 12 4 3 即输入点和数字后 可以再次输入点 且只能是数字或逗号 我
  • Excel 无法在 angularjs 中正确生成

    我在用angularjs并在filesaver js的帮助下使用blob生成excel表我得到了正确的结果 但excel无法在Micrsoft Excel中正确打开 它正在工作 但我没有得到单元格 它显示黑白页面 但内容在那里 帮助如何解决
  • 单元测试 MockHttpServletRequest 不返回内容类型

    我希望应用程序从我的 Java 类返回 JSON 对象 成功和失败情况 我定义了一个 RestControllerAdvice处理来自控制器的错误 我的程序也在json中正确显示错误消息 但问题出在单元测试 问题是当它抛出时 org spr