0°

Spring+Junit+Mock测试web项目,即Controller

准备:Maven依赖


1
2
3
4
5
6
7
8
9
10
11
12
13
14
11 <!-- Spring和MVC的包这里不列出来了,webmvc,aspects,orm,其他maven会自动导 -->
2 2 <dependency>  
3 3             <groupId>junit</groupId>  
4 4             <artifactId>junit</artifactId>  
5 5             <version>4.9</version>  
6 6             <scope>test</scope>  
7 7 </dependency>  
8 8 <dependency>  
9 9             <groupId>org.springframework</groupId>  
1010             <artifactId>spring-test</artifactId>  
1111             <version> 4.1.3.RELEASE</version>  
1212             <scope>provided</scope>  
1313 </dependency>
14

1、控制器例子


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
11 package henu.controller;
2 2
3 3 import org.springframework.stereotype.Controller;
4 4 import org.springframework.web.bind.annotation.RequestMapping;
5 5 import org.springframework.web.bind.annotation.ResponseBody;
6 6
7 7 import henu.entity.Exam;
8 8
9 9 /**
1010  * @ClassName: MockTestController <br/>
1111  * @Describtion: Mock框架测试用例. <br/>
1212  * @date: 2018年4月19日 下午2:02:47 <br/>
1313  * @author Beats <br/>
1414  * @version v1.0
1515  */
1616 @Controller
1717 public class MockTestController {
1818
1919     @RequestMapping("/hello")
2020     @ResponseBody
2121     public String hello(String hello) {
2222         return hello + " world!";
2323     }
2424    
2525     @RequestMapping("/json")
2626     @ResponseBody
2727     public Exam json(String json) {
2828         Exam e = new Exam();
2929         e.setId(123);
3030         e.setSubject(json);
3131         return e;
3232     }
33   }
34

2、测试例子


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
11 package henu.test;
2  2
3  3 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload;
4  4 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
5  5 import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
6  6 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
7  7 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
8  8 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
9  9
10 10 import javax.annotation.Resource;
11 11
12 12 import org.junit.Before;
13 13 import org.junit.Test;
14 14 import org.junit.runner.RunWith;
15 15 import org.springframework.http.MediaType;
16 16 import org.springframework.test.context.ContextConfiguration;
17 17 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
18 18 import org.springframework.test.context.transaction.TransactionConfiguration;
19 19 import org.springframework.test.context.web.WebAppConfiguration;
20 20 import org.springframework.test.web.servlet.MockMvc;
21 21 import org.springframework.test.web.servlet.setup.MockMvcBuilders;
22 22 import org.springframework.transaction.annotation.Transactional;
23 23 import org.springframework.web.context.WebApplicationContext;
24 24
25 25 /**
26 26  * @ClassName: TestMock <br/>
27 27  * @Describtion: 使用Spring集成的Mock框架测试web应用的控制器. <br/>
28 28  * @date: 2018年4月19日 下午1:58:22 <br/>
29 29  * @author Beats <br/>
30 30  * @version v1.0
31 31  */
32 32 //这个必须使用junit4.9以上才有  
33 33 @RunWith(SpringJUnit4ClassRunner.class)  
34 34 //单元测试的时候真实的开启一个web服务,测试完毕就关闭
35 35 @WebAppConfiguration  
36 36 //配置事务的回滚,对数据库的增删改都会回滚,便于测试用例的循环利用  
37 37 @TransactionConfiguration(transactionManager="txManager", defaultRollback=true)  
38 38 @Transactional  
39 39 @ContextConfiguration(locations={"classpath:spring.xml","classpath:springmvc.xml"})  
40 40 //@ContextConfiguration(locations="classpath:spring*.xml")
41 41 public class TestMock {
42 42
43 43     /**
44 44      * web应用的上下文
45 45      */
46 46     @Resource
47 47     private WebApplicationContext context;
48 48     /**
49 49      * Mock框架的核心类
50 50      */
51 51     private MockMvc mockMVC;
52 52
53 53     @Before
54 54     public void initMockMVC() {
55 55         this.mockMVC = MockMvcBuilders.webAppContextSetup(context).build();
56 56     }
57 57
58 58     @Test
59 59     public void testStringResult() throws Exception{
60 60
61 61         String res = mockMVC.perform(get("/hello")
62 62                 .param("hello", "This is my")
63 63                 .contentType(MediaType.TEXT_HTML)
64 64                 .accept(MediaType.TEXT_HTML))
65 65                 .andExpect(status().isOk())//期望值
66 66                 .andDo(print())//打印结果
67 67                 .andReturn().getResponse().getContentAsString();//结果字符串
68 68         System.err.println(res);
69 69
70 70     }
71 71
72 72     @Test
73 73     public void testJsonResult() throws Exception{
74 74
75 75         String res = mockMVC.perform(get("/json")
76 76                 .param("json", "JAVA")
77 77                 .param("hah", "hah")
78 78                 //请求参数的类型
79 79                 .contentType(MediaType.TEXT_HTML)
80 80                 //希望服务器返回的值类型
81 81                 .accept(MediaType.APPLICATION_JSON))
82 82                 .andExpect(status().isOk())//期望值
83 83                 .andDo(print())//打印结果
84 84                 .andReturn().getResponse().getContentAsString();//结果字符串
85 85         System.err.println(res);
86 86     }
87 87
88 88     @Test
89 89     public void testModelResult() throws Exception{
90 90
91 91         String res = mockMVC.perform(get("/json")
92 92                 .param("json", "JAVA")
93 93                 .param("hah", "hah")
94 94                 //请求参数的类型
95 95                 .contentType(MediaType.TEXT_HTML)
96 96                 //希望服务器返回的值类型
97 97                 .accept(MediaType.APPLICATION_JSON))
98 98                     .andExpect(status().isOk())//期望值
99 99                     .andDo(print())//打印结果
100100                     .andReturn().getResponse().getContentAsString();//结果字符串
101101         System.err.println(res);
102102     }
103103    
104104     @Test
105105     public void testOthers() throws Exception {
106106         byte[] bytes = new byte[] {1, 2};  
107107         mockMVC.perform(
108108                 fileUpload("/user/{id}/icon", 1L).file("icon", bytes)) //执行文件上传  
109109                     .andExpect(model().attribute("icon", bytes)) //验证属性相等性  
110110                     .andExpect(view().name("success")); //验证视图  
111111        
112112 //        mockMvc.perform(post("/user").param("name", "zhang")) //执行传递参数的POST请求(也可以post("/user?name=zhang"))  
113113 //        .andExpect(handler().handlerType(UserController.class)) //验证执行的控制器类型  
114114 //        .andExpect(handler().methodName("create")) //验证执行的控制器方法名  
115115 //        .andExpect(model().hasNoErrors()) //验证页面没有错误  
116116 //        .andExpect(flash().attributeExists("success")) //验证存在flash属性  
117117 //        .andExpect(view().name("redirect:/user")); //验证视图  
118118     }
119119 }
120

函数解释:

 


1
2
3
4
5
6
7
8
9
10
11     /**  
22      * perform:执行一个RequestBuilder请求,会自动执行SpringMVC的流程并映射到相应的控制器执行处理;  
33      * get:声明发送一个get请求的方法。MockHttpServletRequestBuilder get(String urlTemplate, Object... urlVariables):根据uri模板和uri变量值得到一个GET请求方式的。另外提供了其他的请求的方法,如:post、put、delete等。  
44      * param:添加request的参数,如上面发送请求的时候带上了了pcode = root的参数。假如使用需要发送json数据格式的时将不能使用这种方式
55      * andExpect:添加ResultMatcher验证规则,验证控制器执行完成后结果是否正确(对返回的数据进行的判断);  
66      * andDo:添加ResultHandler结果处理器,比如调试时打印结果到控制台(对返回的数据进行的判断);  
77      * andReturn:最后返回相应的MvcResult;然后进行自定义验证/进行下一步的异步处理(对返回的数据进行的判断)  
88      */    
9注意上面contentType需要设置成MediaType.APPLICATION_JSON,即声明是发送“application/json”格式的数据。使用content方法,将转换的json数据放到request的body中。
10

 

 

 

没有Mock框架怎么样?

直接使用httpClient或者Okhttp
这方法各种麻烦

使用Spring 提供的RestTemplate
错误不好跟踪,必须开着服务器  

 

在spring开发中,可以使用Spring自带的MockMvc这个类进行Mock测试。

所谓的Mock测试,这里我举一个通俗易懂的例子,像servlet API中的HttpServletRequest对象是Tomcat容器生成的。我们无法手动的new出来,于是就有了所谓的Mock测试

运行配置

用到的注解:

  • RunWith(SpringJUnit4ClassRunner.class): 表示使用Spring Test组件进行单元测试;

  • WebAppConfiguration: 使用这个Annotate会在跑单元测试的时候真实的启动一个web服务,然后开始调用Controller的Rest API,待单元测试跑完之后再将web服务停掉;

  • ContextConfiguration: 指定Bean的配置文件信息,可以有多种方式,这个例子使用的是文件路径形式,如果有多个配置文件,可以将括号中的信息配置为一个字符串数组来表示;

controller,component等都是使用注解,需要注解指定spring的配置文件,扫描相应的配置,将类初始化等。

  • TransactionConfiguration(transactionManager="transactionManager",defaultRollback=true)配置事务的回滚,对数据库的增删改都会回滚,便于测试用例的循环利用

为什么要进行事务回滚:

  • 测试过程对数据库的操作,会产生脏数据,影响我们数据的正确性
  • 不方便循环测试,即假如这次我们将一个记录删除了,下次就无法再进行这个Junit测试了,因为该记录已经删除,将会报错。
  • 如果不使用事务回滚,我们需要在代码中显式的对我们的增删改数据库操作进行恢复,将多很多和测试无关的代码

 

Mock全局配置


1
2
3
4
5
6
7
8
9
11 mockMvc = webAppContextSetup(wac)  
22             .defaultRequest(get("/user/1").requestAttr("default", true)) //默认请求 如果其是Mergeable类型的,会自动合并的哦mockMvc.perform中的RequestBuilder  
33             .alwaysDo(print())  //默认每次执行请求后都做的动作  
44             .alwaysExpect(request().attribute("default", true)) //默认每次执行后进行验证的断言  
55             .build();  
66      
77     mockMvc.perform(get("/user/1"))  
88             .andExpect(model().attributeExists("user"));
9

 

「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!