利用 Junit + MockMvc + Mockito 对 Http 请求进行单元测试

关于 Mockito 以及 模拟(mock)测试 的介绍请直接看下面的文章:
https://www.oschina.net/translate/mockito-a-great-mock-framework-for-java-development
https://www.tianmaying.com/tutorial/JunitForSpringBoot。

在此文主要列举了一些可能在实际中遇到的需要对我们的 Http 请求进行单元测试的例子,包括getpost文件上传等。

环境

基于JDK1.8 + SpringBoot 1.4 + JPA,还需添加:

 

1

2

3

4

5

 

<dependency>

<groupId>commons-io</groupId>

<artifactId>commons-io</artifactId>

<version>2.4</version>

</dependency>

涉及的类和下载:点我
MockMvcController:
其中 @RestController 是 @Controller + @ResponseBody 的注释组合。

 

1

2

3

4

5

6

 

@RestController

@RequestMapping("/mock")

public class MockMvcController {

private final static Logger logger = LoggerFactory.getLogger(MockMvcController.class);

private final static String SUCCESS = "success";

}

MockMvcControllerTest:
单元测试用到的 get()、post()、fileupload() 是 MockMvcRequestBuilders静态方法;content()、status()则是 MockMvcResultMatchers 的方法。

 

1

2

3

4

5

6

7

8

9

10

11

 

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringRunner.class)

@WebMvcTest(MockMvcController.class)

public class MockMvcControllerTest {

private final static ObjectMapper objectMapper = new ObjectMapper();

@Autowired

private MockMvc mockMvc;

}

Role:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

 

@Entity

@Table(name = "roles")

public class Role implements Serializable{

private static final long serialVersionUID = -3181227830551232697L;

@Id

@GeneratedValue

Integer id;

String name;

public Role(){

}

public Role(Integer id,String name) {

this.name = name;

this.id = id;

}

//省略getter、setter和toString()

}

get 请求

在 controller 中写添加一个 get 请求方法:

 

1

2

3

4

5

 

@RequestMapping("/get")

String get(@RequestParam String method){

logger.info("method: {}", method);

return SUCCESS;

}

单元测试:

 

1

2

3

4

5

6

 

@Test

public void testGet() throws Exception{

mockMvc.perform(get("/mock/get?method=testGet")) //参数也可以使用 param("method", "testGet")

.andExpect(status().is(200)) // 请求的状态码是否符合预期

.andExpect(content().string("success"));// 返回的内容是否符合预期

}

测试结果:

method: testGet

post 请求

HttpServletRequest 作为参数

请求:

 

1

2

3

4

5

 

@RequestMapping(value = "/http", method = RequestMethod.POST)

String http(HttpServletRequest request, HttpServletResponse rsponse){

logger.info("Request RemoteAddr: {};", request.getRemoteAddr());

return SUCCESS;

}

单元测试:

 

1

2

3

4

5

6

7

 

@Test

public void testHttp() throws Exception{

mockMvc.perform(post("/mock/http").with(request -> {

request.setRemoteAddr("192.168.0.1");

return request;

}));

}

测试结果:

Request RemoteAddr: 192.168.0.1;

Bean 作为参数

Http 请求:

 

1

2

3

4

5

 

@RequestMapping(value = "/postByBean", method = RequestMethod.POST)

String postByBean(Role role, String method){

logger.info("role: {}; method: {}", role.toString(), method);

return SUCCESS;

}

单元测试:

 

1

2

3

4

5

6

7

8

9

 

@Test

public void testPostByBean() throws Exception{

mockMvc.perform(post("/mock/postByBean")

.param("id", "2")

.param("name", "ROLE_USER")

.param("method", "postByBean"))

.andExpect(status().is(200))

.andExpect(content().string("success"));

}

测试结果:

role: Role{id=2, name=’ROLE_USER’}; method: postByBean

json 作为参数

Http 请求:

 

1

2

3

4

5

 

@RequestMapping(value = "/postByJson", method = RequestMethod.POST)

String postByJson(@RequestBody Role role, String method){

logger.info("role: {}; method: {}", role.toString(), method);

return SUCCESS;

}

单元测试:

 

1

2

3

4

5

6

7

8

 

@Test

public void testPostByJson() throws Exception{

mockMvc.perform(post("/mock/post")

.param("method", "postByJson")

.content(objectMapper.writeValueAsString(new Role(2, "ROLE_USER"))).contentType(MediaType.APPLICATION_JSON)) // json 参数和类型

.andExpect(status().is(200))

.andExpect(content().string("success"));

}

测试结果:

role: Role{id=2, name=’ROLE_USER’}; method: postByJson

文件上传(fileUpload)

Http 请求:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

 

@RequestMapping(value = "/upload", method = RequestMethod.POST)

String upload(@RequestPart(value = "role") Role role,

@RequestParam(value = "file", required = true) List<MultipartFile> files) {

logger.info("role: {};", role.toString());

files.stream().forEach(file -> {

try {

logger.info("filename: {}; originalFilename: {}; content: {}"

, file.getName()

, file.getOriginalFilename()

, IOUtils.toString(file.getInputStream()));

} catch (IOException e) {

e.printStackTrace();

}

});

return SUCCESS;

}

单元测试:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

 

@Test

public void testUpload() throws Exception{

MockMultipartFile jsonFile = new MockMultipartFile("role", "", "application/json","{\"id\":1,\"name\":\"test\"}".getBytes()); //json文件

MockMultipartFile file1 = new MockMultipartFile("file", "filename.txt", "text/plain", "content in file1".getBytes()); //普通文件

MockMultipartFile file2 = new MockMultipartFile("file", "other-file.data", "text/plain", "content in file2".getBytes());

mockMvc.perform(fileUpload("/mock/upload")

.file(jsonFile)

.file(file1).file(file2))

.andExpect(status().is(200))

.andExpect(content().string("success"));

}

测试结果:

role: Role{id=2, name=’ROLE_USER’}; id: 2; name: ROLE_USER
filename: file; originalFilename: filename.txt; content: content in file1
filename: file; originalFilename: other-file.data; file content: content in file2

REST 请求及事务的注入

增加一个实现 JPA 的 Repository 类,不必有具体的实现方法。

 

1

2

 

public interface RoleRepository extends JpaRepository<Role, Integer> {

}

在 Controller 中添加一个实现 Rest 风格的请求方法,并注入 RoleRepository

 

1

2

3

4

5

6

7

8

9

 

@Autowired

private RoleRepository roleRepository;

@RequestMapping("/rest/{id}")

Role rest(@PathVariable Integer id){

Role role = roleRepository.findOne(id);

logger.info("Role Info: {}", role.toString());

return role;

}

单元测试:
@MockBean 此注释被用来添加 mock 对象到 Spring ApplicationContext中。 given() 属于 mockito-core 包,模拟的是请求方法中涉及的数据库操作。

 

1

2

3

4

5

6

7

8

9

10

 

@MockBean

private RoleRepository roleRepository;

@Test

public void testRest()throws Exception{

given(this.roleRepository.findOne(2)).willReturn(new Role(2, "ROLE_USER"));

String contec.perform(get("/mock/rest/2"))

.andExpect(status().is(200)).andReturn().getResponse().getContentAsString();

System.out.println(content);

}

测试结果:

{
“id” : 2,
“name” : “ROLE_USER”
}

除了get()post()fileUpload()外还有patch()put() 和 delete()测试 REST 格式请求的方法。

参考:
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html
http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/mock/mockito/MockBean.html
http://stackoverflow.com/questions/21800726/using-spring-mvc-test-to-unit-test-multipart-post-request

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值