JUnit中使用assertThat断言与MockMvc
定义:
1.JUnit4.*引入了Hamcrest框架,Hamcest提供了一套匹配符Matcher,这些匹配符更接近自然语言,可读性高,更加灵活;
2.使用全新的断言语法:assertThat,结合Hamcest提供的匹配符,只用这一个方法,就可以实现所有的测试;
3.assertThat语法如下:
assertThat(T actual, Matcher matcher);
assertThat(String reason, T actual, Matcher matcher);
其中actual为需要测试的变量,matcher为使用Hamcrest的匹配符来表达变量actual期望值的声明;
4.注意事项:
a.必须导入JUnit4.4之后的版本才能使用assertThat方法;
b.不需要继承TestCase类,但是需要测试方法前必须加“@Test”。
注解:
@Before | 初始化方法 |
---|---|
@After | 释放资源 |
@Test | 测试方法,在这里可以测试期望异常和超时时间 |
@Ignore | 忽略的测试方法 |
@BeforeClass | 针对所有测试,只执行一次,且必须为static void |
@AfterClass | 针对所有测试,只执行一次,且必须为static void |
@RunWith | 指定测试类使用某个运行器 |
@Parameters | 指定测试类的测试数据集合 |
@Rule | 允许灵活添加或重新定义测试类中的每个测试方法的行为 |
@FixMethodOrder | 指定测试方法的执行顺序 |
一个测试类单元测试的执行顺序为:
@BeforeClass –> @Before –> @Test –> @After –> @AfterClass
代码:
sercice代码:
public class DemoService{public int add(int a, int b) {return a+b;}public double div(double a, double b) {return a / b;}public String getName(String name) {return name;}public List<String> getList(String item) {List<String> l = new ArrayList<String>();l.add(item);return l;}public Map<String, String> getMap(String key, String value) {Map<String, String> m = new HashMap<String, String>();m.put(key, value);return m;}}
测试代码
public class Testas {@Testpublic void testAdd() {int s = new DemoService().add(1,2);//allOf:所有条件必须都成立,测试才通过assertThat(s,allOf(greaterThan(1),lessThan(5)));//anyOf:只要有一个条件成立,测试就通过assertThat(s,anyOf(greaterThan(1),lessThan(5)));//anything:无论什么条件,测试都通过assertThat(s, anything());//is:变量的值等于指定值时,测试通过assertThat(s, is(3));//is匹配符简写,is(equalTo(x))的简写,断言testedValue等于expectedValueint testedValue = 6;int expectedValue = 6;assertThat(testedValue, is(expectedValue));//not:和is相反,变量的值不等于指定值时,测试通过assertThat(s, not(1));}@Testpublic void testDiv(){//数值匹配符double d = new DemoService().div(10, 3);//closeTo:浮点型变量的值在3.0±0.5范围内,测试通过assertThat(d, closeTo(3.0, 0.5));//greaterThan:变量的值大于指定值时,测试通过assertThat(d, greaterThan(3.0));//lessThan:变量的值小于指定值时,测试通过assertThat(d, lessThan(3.5));//greaterThanOrEuqalTo:变量的值大于等于指定值时,测试通过assertThat(d, greaterThanOrEqualTo(3.3));//lessThanOrEqualTo:变量的值小于等于指定值时,测试通过assertThat(d, lessThanOrEqualTo(3.4));}@Testpublic void testString(){//字符串匹配符String n = new DemoService().getName("Magci");//containsString:字符串变量中包含指定字符串时,测试通过assertThat(n, containsString("ci"));//startsWith:字符串变量以指定字符串开头时,测试通过assertThat(n, startsWith("Ma"));//endsWith:字符串变量以指定字符串结尾时,测试通过assertThat(n, endsWith("i"));//euqalTo:字符串变量等于指定字符串时,测试通过assertThat(n, equalTo("Magci"));//equalToIgnoringCase:字符串变量在忽略大小写的情况下等于指定字符串时,测试通过assertThat(n, equalToIgnoringCase("magci"));//equalToIgnoringWhiteSpace:字符串变量在忽略头尾任意空格的情况下等于指定字符串时,测试通过assertThat(n, equalToIgnoringWhiteSpace(" Magci "));}@Testpublic void testList(){//集合匹配符List<String> l = new DemoService().getList("Magci");//hasItem:Iterable变量中含有指定元素时,测试通过assertThat(l, hasItem("Magci"));}@Testpublic void testMap(){Map<String, String> m = new DemoService().getMap("tr", "String");//hasEntry:Map变量中含有指定键值对时,测试通过assertThat(m, hasEntry("tr", "String"));//hasKey:Map变量中含有指定键时,测试通过assertThat(m, hasKey("tr"));//hasValue:Map变量中含有指定值时,测试通过assertThat(m, hasValue("String"));}
}@Testpublic void testClass(){DemoServicedemoas = new DemoService();//is(instanceOf(XXX.class)):断言demoas为Demoas的实例assertThat(demoas,is(instanceOf(DemoService.class)));//isA(xxx.class):是is(instanceOf(XXX.class))的简写assertThat(demoas,isA(DemoService.class));}
如何测试抛出异常
方法一:注解上添加异常类Error.class或者Exception.class
@RunWith(SpringRunner.class)
@SpringBootTest
public class Testas {@Test(expected = Error.class)public void testAdd() {}
}
方法二:直接抛出,抛出以下的代码不执行
@Testpublic void testAdd() {int s = new DemoService().add(1,2);//allOf:所有条件必须都成立,测试才通过assertThat(s,allOf(greaterThan(1),lessThan(5)));throw new Error();}
注:两个方法可以同时存在,但是要保证上下抛出的异常一致性
@Test(expected = Error.class)public void testAdd() {int s = new DemoService().add(1,2);//allOf:所有条件必须都成立,测试才通过assertThat(s,allOf(greaterThan(1),lessThan(5)));throw new Error();}
错误示范:会导致异常不通过
@Test(expected = Exception.class)public void testAdd() {int s = new DemoService().add(1,2);//allOf:所有条件必须都成立,测试才通过assertThat(s,allOf(greaterThan(1),lessThan(5)));throw new Error();}
MockMvc的用法
代码包括:
上面的service代码
Controller代码:
@RestController
public class DemoController {@Autowiredprivate DemoService demoService;@GetMapping("/test/{a}/{b}")public int addCon(@PathVariable int a, @PathVariable int b){return demoService.add(a,b);}
}
测试代码:
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class TestMock {@Autowiredprivate MockMvc mvc;@Testpublic void testMocks() throws Exception {mvc.perform(MockMvcRequestBuilders.get("/test/5/6").contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaType.APPLICATION_JSON_UTF8)).andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().string("11")).andDo(MockMvcResultHandlers.print());}
测试结果:
整个过程:
- mockMvc.perform执行一个请求;
- MockMvcRequestBuilders.get("/user/1")构造一个请求
- ResultActions.andExpect添加执行完成后的断言
- ResultActions.andDo添加一个结果处理器,表示要对结果做点什么事情,比如此处使用
- MockMvcResultHandlers.print()输出整个响应结果信息。
- ResultActions.andReturn表示执行完成后返回相应的结果。
注:
这一步集成Web环境测试需要在Test方法之前使用,但是可以替代,如下:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:config/IncotermsRestServiceTest-context.xml")
@WebAppConfiguration
public class IncotermsRestServiceTest {@Autowiredprivate WebApplicationContext wac;private MockMvc mockMvc;@Beforepublic void setup() {this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); //构造MockMvc}...
}
替代:
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class TestMock {@Autowiredprivate MockMvc mvc;
}
MockMvc如何抛出异常
添加注解属性
可以指定抛出的类型,如果一致则通过。但是会在某个位置抛出,不一定特定的某行提示异常信息
业务层
public TestEntity adds(){TestEntity testEntity1 = new TestEntity();testEntity1.setAuthor("测试");testEntity1.setTitle("第一次");return testEntity1;}
controller层
@GetMapping("/test")public TestEntity addCon(){return demoService.adds();}
测试层
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class TestMock {@Autowiredprivate MockMvc mvc;@Rulepublic ExpectedException thrown = ExpectedException.none();@Testpublic void throwsNothing(){//没有预期的例外,没有抛出:传递。}@Testpublic void testMocks() throws Exception {ResultActions persform =mvc.perform(MockMvcRequestBuilders.get("/test/5/6").contentType(MediaType.APPLICATION_JSON_UTF8).accept(MediaType.APPLICATION_JSON_UTF8));persform.andExpect(MockMvcResultMatchers.status().isOk()).andExpect(MockMvcResultMatchers.content().string("11"));thrown.expect(AssertionError.class);thrown.expectMessage("JSON path\"$.author\"");persform.andExpect(MockMvcResultMatchers.jsonPath("$.author").value("测试1"));persform.andExpect(MockMvcResultMatchers.jsonPath("$.title").value("第一次"));}
}
此时运行结果是:
你必须将ExpectedException规则添加到测试中。这不会影响你现有的测试。在指定预期异常的类型后,如果抛出此类异常,则测试成功,如果抛出异常或没有异常则失败。
assertThat断言主要用来测试Service层
MockMvc主要用来测试Controller层
*打包测试
如果是需要多个单元测试类整合测试 使用一个Runner进行异步测试,只需要把相关的class放入到SuiteClasses{}中即可,如:JunitTest.class 和 TestClassDemo.class 都是写好的单元测试类.
@RunWith(Suite.class)
@SpringBootTest
@Suite.SuiteClasses({Testas.class,TestMock.class
})
public class DemoApplicationTests {//不需要写任何代码
}
结果:
一些常用的测试
测试普通控制器
mockMvc.perform(get("/user/{id}", 1)) //执行请求 .andExpect(model().attributeExists("user")) //验证存储模型数据 .andExpect(view().name("user/view")) //验证viewName .andExpect(forwardedUrl("/WEB-INF/jsp/user/view.jsp"))//验证视图渲染时forward到的jsp .andExpect(status().isOk())//验证状态码 .andDo(print()); //输出MvcResult到控制台
得到MvcResult自定义验证
MvcResult result = mockMvc.perform(get("/user/{id}", 1))//执行请求 .andReturn(); //返回MvcResult
Assert.assertNotNull(result.getModelAndView().getModel().get("user")); //自定义断言
验证请求参数绑定到模型数据及Flash属性
mockMvc.perform(post("/user").param("name", "zhang")) //执行传递参数的POST请求(也可以post("/user?name=zhang")) .andExpect(handler().handlerType(UserController.class)) //验证执行的控制器类型 .andExpect(handler().methodName("create")) //验证执行的控制器方法名 .andExpect(model().hasNoErrors()) //验证页面没有错误 .andExpect(flash().attributeExists("success")) //验证存在flash属性 .andExpect(view().name("redirect:/user")); //验证视图
文件上传
byte[] bytes = new byte[] {1, 2};
mockMvc.perform(fileUpload("/user/{id}/icon", 1L).file("icon", bytes)) //执行文件上传 .andExpect(model().attribute("icon", bytes)) //验证属性相等性 .andExpect(view().name("success")); //验证视图
JSON请求/响应验证
String requestBody = "{\"id\":1, \"name\":\"zhang\"}"; mockMvc.perform(post("/user") .contentType(MediaType.APPLICATION_JSON).content(requestBody) .accept(MediaType.APPLICATION_JSON)) //执行请求 .andExpect(content().contentType(MediaType.APPLICATION_JSON)) //验证响应contentType .andExpect(jsonPath("$.id").value(1)); //使用Json path验证JSON 请参考http://goessner.net/articles/JsonPath/ String errorBody = "{id:1, name:zhang}"; MvcResult result = mockMvc.perform(post("/user") .contentType(MediaType.APPLICATION_JSON).content(errorBody) .accept(MediaType.APPLICATION_JSON)) //执行请求 .andExpect(status().isBadRequest()) //400错误请求 .andReturn(); Assert.assertTrue(HttpMessageNotReadableException.class.isAssignableFrom(result.getResolvedException().getClass()));//错误的请求内容体
异步测试
//Callable
MvcResult result = mockMvc.perform(get("/user/async1?id=1&name=zhang")) //执行请求 .andExpect(request().asyncStarted()) .andExpect(request().asyncResult(CoreMatchers.instanceOf(User.class))) //默认会等10秒超时 .andReturn(); mockMvc.perform(asyncDispatch(result)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.id").value(1));
全局配置
mockMvc = webAppContextSetup(wac) .defaultRequest(get("/user/1").requestAttr("default", true)) //默认请求 如果其是Mergeable类型的,会自动合并的哦mockMvc.perform中的RequestBuilder .alwaysDo(print()) //默认每次执行请求后都做的动作 .alwaysExpect(request().attribute("default", true)) //默认每次执行后进行验证的断言 .build(); mockMvc.perform(get("/user/1")) .andExpect(model().attributeExists("user"));
参考:https://www.jianshu.com/p/91045b0415f0
参考:https://blog.csdn.net/wangpeng047/article/details/9628449
参考: https://my.oschina.net/u/2349331/blog/471247
JUnit中使用assertThat断言与MockMvc相关推荐
- JUnit中测试异常抛出的方法
最近在做TWU关于TDD的作业,对JUnit中测试异常抛出的方法进行了一些学习和思考. 在进行单元测试的时候有的时候需要测试某一方法是否抛出了正确的异常.例如,我有一个方法,里面对一个List进行读取 ...
- junit:junit_处理JUnit中异常的另一种方法:catch-exception
junit:junit JUnit中有许多处理异常的方法 (JUnit中有3种处理异常的方法.选择哪一种? JUnit ExpectedException规则:超越了基础 ). 在这篇文章中,我将介绍 ...
- junit 5测试异常处理_在JUnit中处理异常的3种方式。 选择哪一个?
junit 5测试异常处理 在JUnit中,有3种流行的方式来处理测试代码中的异常: 试捕习语 使用JUnit规则 带注解 我们应该使用哪一个?何时使用? 试捕习语 这个习语是最受欢迎的习语之一,因为 ...
- 处理JUnit中异常的另一种方法:catch-exception
JUnit中有许多处理异常的方法 (JUnit中有3种处理异常的方法.选择哪一种呢? JUnit ExpectedException规则:超越了基础 ). 在本文中,我将介绍建议尝试的catch-ex ...
- 在JUnit中测试预期的异常
单元测试用于验证一段代码是否按照开发人员的预期运行. 有时,这意味着检查代码是否也会引发预期的异常. JUnit是Java单元测试的标准,并提供了几种验证抛出异常的机制. 本文探讨了这些选项及其相对优 ...
- 在JUnit中处理异常的3种方法。 选择哪一个?
在JUnit中,有3种流行的方式来处理测试代码中的异常: 尝试捕捉习语 使用JUnit规则 带注解 我们应该使用哪一个?何时使用? 尝试捕捉习语 这个习语是最受欢迎的习语之一,因为它已在JUnit 3 ...
- junit5_在JUnit中测试预期的异常
junit5 单元测试用于验证一段代码是否按照开发人员的预期运行. 有时,这意味着检查代码是否也会引发预期的异常. JUnit是Java单元测试的标准,并提供了几种验证抛出异常的机制. 本文探讨了这些 ...
- eclipse/myeclipse中如何开启断言调试代码
转载:http://blog.csdn.net/emperorjade/article/details/32140763 assertion(断言)在软件开发中是一种常用的调试方式,很多开 ...
- junit rule_使用@Rule在JUnit中测试文件和目录
junit rule 多亏了TemporaryFolder @Rule在JUnit中使用文件和目录进行测试很容易. 在JUnit中,规则( @Rule )可以用作夹具设置和清除方法( org.juni ...
最新文章
- 通俗理解tf.name_scope()、tf.variable_scope()
- 查询自己OpenGL的版本信息
- c语言求最多啤酒数,C语言,算法、动态规划:有一个箱子的容量为v(正整数,0=v=20000),同时有n个物品(0n=30),...
- 微软协助谷歌开发ARM平台Chrome浏览器
- 做项目时的几个感慨(持续更新...)
- Oracle Database 20c 十大新特性一览
- 理解为什么要使用Ioc
- 用postGIS向postgresql插入空间数据
- 解决C++中multiple definition of问题
- java的几个设计模式
- C#窗体控件—textbox
- Qt中配置OpenCV
- NSString+NSMutableString+NSValue+NSAraay用法汇总
- 替代CH7511B DP转LVDS屏换接设计|替代CH7511B EDP转LVDS转接板电路|CS5211电路原理图
- js与朴php订单评价功能
- elementui级联选择器Cascader不触发change事件
- 电脑快捷键【Crtl】
- 2022-2027年(新版)中国大米行业营销战略与供应情况预测报告
- 20211212做实验时的感想
- 数据库mysql---NUMERIC数据类型