Springboot---mockMVC进行Controller单元测试
知识准备
1、注解含义
@RunWith(SpringRunner.class):表示使用Spring Test组件进行单元测试,其中SpringRunner继承类SpringJUnit4ClassRunner。
@WebAppConfiguration:测试环境使用,用来表示测试环境使用的ApplicationContext将是WebApplicationContext类型的;value指定web应用的根;
@AutoConfigureMockMvc:注入一个MockMvc实例;
注入web环境的ApplicationContext容器:mvc = MockMvcBuilders.webAppContextSetup(context).build();
2、fastjson转换--对象字段值为null的json化
//方式一:
/**
* 自定义jason转换字段过路规则
*/
ValueFilter filter = new ValueFilter() {
@Override
public Object process(Object object, String name, Object value) {
if (value == null)
return "";//如果字段的值为空则用空字符串代替
return value;
}
};
JSONObject.toJSONString(lisList,filter )
// 方式二:
// 如果lisList字段的值为空,则用null表示
JSONObject.toJSONString(lisList,SerializerFeature.WriteMapNullValue)
单元测试
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
代码
1、jsonPath("$.result")的规则项目地址:https://github.com/json-path/JsonPath
2、使用ObjectMapper等同于对Girl对象直接赋值再转换为json格式。
@RunWith(SpringRunner.class)
@SpringBootTest// 此处若不指定,则默认为src/main/java/下面的启动类
public class TermControllerTest {
private MockMvc mockMvc;
private static final String PREFIX_URI = "XXXXXXX";
/**
* 注入WebApplicationContext
*/
@Autowired
private WebApplicationContext webApplicationContext;
/**
* 模拟MVC对象,通过MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build()初始化
*/
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(
this.webApplicationContext).build();
}
/**
* 获取所有字典类别,类型为basicitems
*
* @throws Exception
*/
@Test
public void loadTermsByTypes() throws Exception {
String uri = PREFIX_URI + "/basic/getList" + "?types=changestatus";
// 构造返回值对象
Response<List<List<Map<String, String>>>> fpoResponse = new FpoResponse<>();
Response.setCode("xxx");
... ...
// 模拟GET请求
MvcResult mvcResult = this.mockMvc
.perform(MockMvcRequestBuilders.get(uri))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(// 校验自定义的状态码
MockMvcResultMatchers.jsonPath("$.code").value(
"xxxxxxx"))
.andExpect(
MockMvcResultMatchers.content().contentType(
MediaType.APPLICATION_JSON_UTF8))
.andExpect(
MockMvcResultMatchers.jsonPath("$.result").value(// 获取所有结果
JSONObject.toJSONString(lisList,// 指定空字符串也进行转换
SerializerFeature.WriteMapNullValue)))
.andReturn();// 获取返回结果
/**
* 自定义jason转换字段过路规则
*/
ValueFilter filter = new ValueFilter() {
@Override
public Object process(Object object, String name, Object value) {
if (value == null)
return "";
return value;
}
};
// 打印返回结果
System.out.println(JSONObject.toJSONString(Response,
SerializerFeature.WriteMapNullValue));
System.out.println(mvcResult.getResponse().getContentAsString());
}
@Test
public void addGirl() throws Exception {
// Girl girl = new Girl();
// girl.setCupSize("B");
// girl.setAge(19);
// girl.setMoney(22.22);
//ObjectMapper 是一个可以重复使用的对象
ObjectMapper mapper = new ObjectMapper();
String jsonString = "{\"cupSize\":\"B\", \"age\":19, \"money\":22.22}";
//将JSON字符串值转换成 Girl对象里的属性值
Girl girl = mapper.readValue(jsonString, Girl.class);
mvc.perform(MockMvcRequestBuilders.post("/girlsss")
.contentType(MediaType.APPLICATION_JSON_UTF8)
/* 使用writeValueAsString() 方法来获取对象的JSON字符串表示 */
.content(mapper.writeValueAsString(girl)))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(MockMvcResultMatchers.jsonPath(
"$.cupSize").value("B"))
.andExpect(MockMvcResultMatchers.jsonPath(
"$.age").value(19))
.andExpect(MockMvcResultMatchers.jsonPath(
"$.money").value(22.22));
}
}
单元测试事务
junit 单元测试事务会自动回滚。通过@Rollback(true)注解来实现,默认是true,事务会回滚,可以不写。false时事务不会回滚,数据会写到数据库中。
把@Transactional
也去掉再运行测试,结果在数据库中查询到了被插入的数据
结论:在JUnit4的测试方法中打事务注解@Transactional
,默认会按照@Rollback(true)
来进行处理,无论如何都会回滚,打不打注解@Rollback
或@Rollback(true)
已经不重要了。而在@Transactional
的基础上加上@Rollback(false)
之后,效果就好像是单单这个测试函数这一层没有打事务似的,而不会传播到嵌套的service层的事务内,即如果在service层的事务中,插入数据后又发生异常,最终在service层里还是会进行rollback,数据并不会插入到数据库中。
Case 1: 插入成功后会回滚
输出:insert :1 rows!
Rolled back transaction after test execution for test context......
@Test
@Transactional
public void testTx() throws Exception{
User user = new User();
user.setUsername("zhuqiuhui-testTx");
user.setAddress("河南省上蔡县-testTx");
user.setBirthday(new Date());
user.setSex("男-testTx");
int num = iUserService.insertUser(user);
assert(num==1);
System.out.println("insert :" + num + " rows!");
}
Case 2: 正常插入,此过程若(1)处抛出异常(不论Exception、RuntimeException或者FileNotFoundException等)均正常插入,事务并不回滚
@Test
@Transactional
@Rollback(false)
public void testTx() throws Exception{
User user = new User();
user.setUsername("zhuqiuhui-testTx");
user.setAddress("河南省上蔡县-testTx");
user.setBirthday(new Date());
user.setSex("男-testTx");
int num = iUserService.insertUser(user);--------(1)
assert(num==1);
System.out.println("insert :" + num + " rows!");
}