12 testing json mocking mockito spring-boot
我发现这个代码来测试 json 字符串是否等于另一个字符串
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class MockMvcExampleTests {
@Autowired
private MockMvc mvc;
@Test
public void exampleTest() throws Exception {
this.mvc.perform(get("/")).andExpect(status().isOk())
.andExpect(content().string("Hello World"));
}
}
Run Code Online (Sandbox Code Playgroud)
你知道如何测试json结构吗?就像检查对象是否包含 id、name、age...无论值是什么。谢谢。
use*_*710 13
验证正确响应的最佳方法JSON取决于您的响应。
例如,假设您有一个@Controller(或@RestController) 访问 a @Repository(直接或通过 a 间接访问@Service)并将结果项映射到JSON。例如:
public class MyPojo {
private int id;
private String name;
private int age;
// no-args for deserialization, required by some Frameworks with default settings
public MyPojo() {}
// constructor
public MyPojo(final int id, final String name, final int age) { ... }
// Getters
public int getid() { ... }
public String getName() { ... }
public int getName() { ... }
}
Run Code Online (Sandbox Code Playgroud)
@Repository
public class MyRepository {
public MyPojo findMyPojoById(final int id) { return db.findById(id); }
}
Run Code Online (Sandbox Code Playgroud)
@RestController
@RequestMapping("/")
public class MyController {
@Autowired
private MyRepository repository;
@GetMapping
public MyPojo findMyPojoById(@RequestParam final int id) {
return repository.findMyPojoByid(id);
}
}
Run Code Online (Sandbox Code Playgroud)
那么GET请求?id=1可能会返回如下内容:
{
"id": 1,
"name": "John",
"age": 12
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,你有多种选择。在mockMvc测试中,您通常对测试组件的集成不感兴趣,只想测试控制器是否按预期工作。在这种情况下,您可能需要一个单元测试,并模拟存储库。您有一些选择:
在这种情况下,您可以执行以下操作:
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class MockMvcExampleTests {
@Autowired
private MockMvc mvc;
@MockBean
private MyRepository repository; // mock the repository
@Autowired
private ObjectMapper objectMapper;
@Test
public void exampleTest() throws Exception {
final int userId = 1;
MyPojo mockedUser = new MyPojo(userId, "John", 12);
Mockito.doReturn(mockedUser).when(repository).findMyPojoById(userId);
final String expectedResponseContent = objectMapper.writeValueAsString(mockedUser);
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(content().json(expectedResponseContent ));
verify(repository).findMyPojoById(userId); // verify that the repository was called correctly
}
}
Run Code Online (Sandbox Code Playgroud)
这样做的好处是测试更加稳健。如果您的MyPojo对象发生更改,只要您不更新测试中模拟对象的所有构造函数用法,您的测试就会失败 - 这是一个有争议的问题,因为只有您更新后,代码才会编译。
jsonPath()在这种情况下,您可以使用jsonPath(一种计算结构上表达式的方法JSON,类似于XPathfor XML)来单独计算结构的部分或全部部分JSON。
例如(仍然嘲笑响应):
@Test
public void exampleTest() throws Exception {
final int userId = 1;
MyPojo mockedUser = new MyPojo(userId, "John", 12);
Mockito.doReturn(mockedUser).when(repository).findMyPojoById(userId); // note that this mock is not necessary, but it does make the test a unit test
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id", is(userId))) // is(<Object>) is e.g. a Hamcrest Matcher
.andExpect(jsonPath("$.name", is("John"))
.andExpect(jsonPath("$.age", is(12)))
verify(repository).findMyPojoById(userId);
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果您有一个响应对象数组,您可以使用正确的数组表示法来解析它们,例如:
.andExpect(jsonPath("$[0].name", is("Mary")))
Run Code Online (Sandbox Code Playgroud)
这样做的好处是您不必评估整个响应。例如,如果服务器响应包含服务器生成的数据,而这些数据在不消除太多实际代码逻辑(例如通过模拟)的情况下难以复制或模拟,则这可能很有用。在这种情况下,您可以检查该字段是否存在,而不考虑其实际值,例如:
.andExpect(jsonPath("$.serverGeneratedSecretKey", notNullValue()))
Run Code Online (Sandbox Code Playgroud)
最后,您可以比较实际的响应:
String expectedResponse = "{\"id\": 1, \"name\":\"John\", \"age\": 12}";
String responseString = mockMvc.perform(...)
.andExpect(status().isOk())
.andReturn()
.getResponse()
.getContentAsString();
assertEquals("Response does not match", expectedResponse, responseString);
Run Code Online (Sandbox Code Playgroud)
然而,这种方式非常善变:
JSON 完全匹配,其中包括转义"和适当的空白。ObjectMapper尝试遵循 JSON 字段出现的顺序,但您永远不应该根据 JSON 对象的顺序工作代码(除了数组之外,JSON未定义顺序)我想不出这种方法的一个很好的用例,但是,好吧 - 如果你想要它,它就在那里。
有趣的是,Java13终于支持文本块了。这些块虽然可以更轻松地编写预期的响应字符串,但对其他方面没有帮助。
| 归档时间: |
|
| 查看次数: |
18101 次 |
| 最近记录: |