Spring Boot之 单元测试总结

版权声明:转载注明出处 https://blog.csdn.net/jy02268879/article/details/83346701

一、IDEA自动生成测试类

1.安装插件JUnitGenerator V2.0

File---->Settings---->Browse Repositories

2.安装好后把JUnit和JUnitGenerator V2.0一起勾上

3.配置插件

把package上test.前缀去掉

配置测试类生成的地址

${SOURCEPATH}/../../test/java/${PACKAGE}/${FILENAME}

4.对着要生成的类

二、测试service类

@SpringBootTest会加载spring的上下文,这样可以使用@Autowired注入Bean


 
 
  1. package com.sid.service.impl;
  2. import com.sid.service.UserService;
  3. import org.junit.After;
  4. import org.junit.Assert;
  5. import org.junit.Before;
  6. import org.junit.Test;
  7. import org.junit.runner.RunWith;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.boot.test.context.SpringBootTest;
  10. import org.springframework.test.context.junit4.SpringRunner;
  11. import static org.hamcrest.CoreMatchers.*;
  12. import static org.junit.Assert.*;
  13. /**
  14. * @Description: Service层单元测试 启动了服务
  15. * @Param:
  16. * @return:
  17. * @Author: Sid
  18. * @Date: 2018-10-24 13:53
  19. * @since: 1.0
  20. */
  21. @RunWith(SpringRunner.class)
  22. @SpringBootTest
  23. public class UserServiceImplTest {
  24. /**
  25. * @Description: 直接测试service 用IOC注入进来 这样run的时候会先启动springboot项目
  26. * @Param:
  27. * @return:
  28. * @Author: Sid
  29. * @Date: 2018-10-24 13:42
  30. * @since: 1.0
  31. */
  32. @Autowired
  33. UserService userService;
  34. @Before
  35. public void setUp() throws Exception {
  36. }
  37. @After
  38. public void tearDown() throws Exception {
  39. }
  40. @Test
  41. public void set() {
  42. userService.set( "sid:test:string:key:", "lalala");
  43. String value = userService.get( "sid:test:string:key:");
  44. Assert.assertEquals( "lalala",value);
  45. //可以只使用 assertThat 一个断言语句,结合 Hamcrest 提供的匹配符,就可以表达全部的测试思想
  46. //引入import static org.hamcrest.CoreMatchers.*;
  47. Assert.assertThat(value,is( "lalala"));
  48. }
  49. }

三、测试Controller类

有3种方法,1可以跟上面一样用@Autowired把Controller注入进来然后调用Controller的方法。参照上方,这里不介绍。

2.用MockMvc模拟的HTTP请求


 
 
  1. package com.sid.controller;
  2. import org.junit.After;
  3. import org.junit.Before;
  4. import org.junit.Test;
  5. import org.junit.runner.RunWith;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.boot.test.context.SpringBootTest;
  8. import org.springframework.http.MediaType;
  9. import org.springframework.test.context.junit4.SpringRunner;
  10. import org.springframework.test.web.servlet.MockMvc;
  11. import org.springframework.test.web.servlet.MvcResult;
  12. import org.springframework.test.web.servlet.ResultActions;
  13. import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
  14. import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
  15. import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
  16. import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
  17. import org.springframework.test.web.servlet.setup.MockMvcBuilders;
  18. import org.springframework.web.context.WebApplicationContext;
  19. import static org.hamcrest.CoreMatchers.*;
  20. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
  21. /**
  22. * @Description: Controller层单元测试 注入Spring 上下文的环境到 MockMvc 中 测试时会启动项目
  23. * @Param:
  24. * @return:
  25. * @Author: Sid
  26. * @Date: 2018-10-24 13:45
  27. * @since: 1.0
  28. */
  29. @RunWith(SpringRunner.class)
  30. @SpringBootTest
  31. public class UserControllerTest {
  32. /**
  33. * @Description: 使用MockMvc 模拟HTTP请求 来测试controller
  34. * MockMvc实现了对Http请求的模拟,能够直接使用网络的形式,转换到Controller的调用,
  35. * 这样可以使得测试速度快、不依赖网络环境,而且提供了一套验证的工具,这样可以使得请求的验证统一而且很方便。
  36. *
  37. * // 模拟MVC对象,通过MockMvcBuilders.webAppContextSetup(this.wac).build()初始化。
  38. * @Param:
  39. * @return:
  40. * @Author: Sid
  41. * @Date: 2018-10-24 13:43
  42. * @since: 1.0
  43. */
  44. private MockMvc mvc;
  45. @Autowired
  46. private WebApplicationContext wac; // 注入WebApplicationContext
  47. /**
  48. * @Description: 直接注入userController 然后调用userController的方法来测试
  49. * @Param:
  50. * @return:
  51. * @Author: Sid
  52. * @Date: 2018-10-24 13:44
  53. * @since: 1.0
  54. */
  55. // @Autowired
  56. // private UserController userController;
  57. @Before
  58. public void setUp() throws Exception {
  59. //使用 WebApplicationContext 构建 MockMvc
  60. this.mvc = MockMvcBuilders.webAppContextSetup( this.wac).build();
  61. }
  62. @After
  63. public void tearDown() throws Exception {
  64. }
  65. @Test
  66. public void addUser() throws Exception {
  67. MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post( "/user/add")
  68. .contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
  69. //form表单格式传参
  70. .param( "id", "4")
  71. .param( "name", "junit test")
  72. .param( "password", "111")
  73. .param( "mobilePhone", "18523980000")
  74. .characterEncoding( "utf-8")
  75. .accept(MediaType.APPLICATION_JSON_UTF8_VALUE);
  76. ResultActions result = mvc.perform(requestBuilder);
  77. MvcResult mvcResult = result.andExpect(MockMvcResultMatchers.status().isOk())
  78. .andDo(MockMvcResultHandlers.print())
  79. .andReturn(); // 返回执行请求的结果
  80. System.out.println( "response------------------:"+mvcResult.getResponse().getContentAsString());
  81. }
  82. @Test
  83. public void deleteUser() throws Exception {
  84. MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post( "/user/delete")
  85. .contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
  86. //form表单格式传参
  87. .param( "mobilePhone", "18523980000")
  88. .characterEncoding( "utf-8")
  89. .accept(MediaType.APPLICATION_JSON_UTF8_VALUE);
  90. ResultActions result = mvc.perform(requestBuilder);
  91. MvcResult mvcResult = result.andExpect(MockMvcResultMatchers.status().isOk())
  92. .andExpect(MockMvcResultMatchers.jsonPath( "$").value( 1))
  93. .andDo(MockMvcResultHandlers.print())
  94. .andReturn(); // 返回执行请求的结果
  95. System.out.println( "response------------------:"+mvcResult.getResponse().getContentAsString());
  96. }
  97. @Test
  98. public void updateUser() throws Exception {
  99. MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post( "/user/update")
  100. .contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
  101. //form表单格式传参
  102. .param( "id", "1")
  103. .param( "name", "李沂桀")
  104. .param( "mobilePhone", "185")
  105. .param( "password", "5")
  106. .characterEncoding( "utf-8")
  107. .accept(MediaType.APPLICATION_JSON_UTF8_VALUE);
  108. ResultActions result = mvc.perform(requestBuilder);
  109. MvcResult mvcResult = result.andExpect(MockMvcResultMatchers.status().isOk())
  110. .andDo(MockMvcResultHandlers.print())
  111. .andReturn(); // 返回执行请求的结果
  112. System.out.println( "response------------------:"+mvcResult.getResponse().getContentAsString());
  113. }
  114. @Test
  115. public void selectAll() throws Exception {
  116. MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post( "/user/selectAll")
  117. .contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
  118. //form表单格式传参
  119. .param( "pageNum", "1")
  120. .param( "pageSize", "5")
  121. .characterEncoding( "utf-8")
  122. .accept(MediaType.APPLICATION_JSON_UTF8_VALUE);
  123. ResultActions result = mvc.perform(requestBuilder);
  124. MvcResult mvcResult = result.andExpect(MockMvcResultMatchers.status().isOk())
  125. .andExpect(jsonPath( "list").exists())
  126. .andExpect(jsonPath( "$.list", notNullValue()))
  127. .andExpect(jsonPath( "$.list[0].id", is( 1)))
  128. .andDo(MockMvcResultHandlers.print())
  129. .andReturn(); // 返回执行请求的结果
  130. System.out.println( "response------------------:"+mvcResult.getResponse().getContentAsString());
  131. }
  132. @Test
  133. public void getUserByMobilePhone() throws Exception {
  134. MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post( "/user/getUserByMobilePhone")
  135. .contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
  136. //form表单格式传参
  137. .param( "mobilePhone", "18523980000")
  138. .characterEncoding( "utf-8")
  139. .accept(MediaType.APPLICATION_JSON_UTF8_VALUE);
  140. ResultActions result = mvc.perform(requestBuilder);
  141. MvcResult mvcResult = result.andExpect(MockMvcResultMatchers.status().isOk())
  142. .andExpect(jsonPath( "$", notNullValue()))
  143. .andExpect(jsonPath( "$.name", is( "junit test")))
  144. .andDo(MockMvcResultHandlers.print())
  145. .andReturn(); // 返回执行请求的结果
  146. System.out.println( "response------------------:"+mvcResult.getResponse().getContentAsString());
  147. }
  148. }

3.用TestRestTemplate 完整HTTP请求测试


 
 
  1. package com.sid.controller;
  2. import com.github.pagehelper.PageInfo;
  3. import com.sid.model.User;
  4. import org.hamcrest.Matchers;
  5. import org.junit.Assert;
  6. import org.junit.Test;
  7. import org.junit.runner.RunWith;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.boot.test.context.SpringBootTest;
  10. import org.springframework.boot.test.web.client.TestRestTemplate;
  11. import org.springframework.core.ParameterizedTypeReference;
  12. import org.springframework.http.HttpEntity;
  13. import org.springframework.http.HttpHeaders;
  14. import org.springframework.http.HttpMethod;
  15. import org.springframework.http.ResponseEntity;
  16. import org.springframework.test.context.junit4.SpringRunner;
  17. import org.springframework.util.LinkedMultiValueMap;
  18. import org.springframework.util.MultiValueMap;
  19. /**
  20. * @program: springboot
  21. * @description:
  22. * @author: Sid
  23. * @date: 2018-11-15 10:52
  24. * @since: 1.0
  25. **/
  26. @RunWith(SpringRunner.class)
  27. //开启一个随机的可用端口
  28. @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
  29. public class TestRestTemplateTest {
  30. @Autowired
  31. private TestRestTemplate restTemplate;
  32. @Test
  33. public void listAll() {
  34. String url = "/user/selectAll";
  35. // 封装入参数,不要替换为Map与HashMap,否则参数无法传递
  36. MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
  37. paramMap.add( "pageNum", 1);
  38. paramMap.add( "pageSize", 5);
  39. HttpHeaders headers = new HttpHeaders();
  40. HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(paramMap,headers);
  41. // 1、使用postForObject请求接口
  42. PageInfo<User> result = restTemplate.postForObject(url, paramMap, PageInfo.class);
  43. System.out.println( "result1==================" + result.getList());
  44. // 2、使用postForEntity请求接口
  45. ResponseEntity<PageInfo> response2 = restTemplate.postForEntity(url, httpEntity, PageInfo.class);
  46. System.out.println( "result2====================" + response2.getBody().getList());
  47. // 3、使用exchange请求接口
  48. //设置接受参数的类型 只有用exchange+ParameterizedTypeReference接收到的pageInfo中的List是user类,上面两种方式接收到的都是个LinkedList
  49. ParameterizedTypeReference<PageInfo<User>> type = new ParameterizedTypeReference<PageInfo<User>>() {};
  50. ResponseEntity<PageInfo<User>> response3 = restTemplate.exchange(url, HttpMethod.POST, httpEntity, type);
  51. System.out.println( "result3====================" + response3.getBody().getList());
  52. Assert.assertThat(response3.getBody().getList(), Matchers.notNullValue());
  53. }
  54. }

四、常用注解介绍

@Before:初始化方法
@After:释放资源
@Test:测试方法(包括:期望异常和超时时间)

@Test(timeout = 1000),超时会失败。

@Test(expected = NullPointerException.class) 希望抛出空指针异常


@Ignore:忽略的测试方法
@BeforeClass:针对所有测试,只执行一次,且必须为static void
@AfterClass:针对所有测试,只执行一次,且必须为static void
@RunWith:可以更改测试运行器
执行顺序:

@BeforeClass ==> @Before ==> @Test ==> @After ==> @AfterClass 

 

@SpringBootTest会加载spring的上下文,这样可以使用@Autowired注入Bean

 

五、参数化测试

1.使用parameterized入参

每一组参数执行一次test的入参


 
 
  1. package com.sid.controller;
  2. import org.junit.Test;
  3. import org.junit.runner.RunWith;
  4. import org.junit.runners.Parameterized;
  5. import java.util.Arrays;
  6. import java.util.List;
  7. import static org.hamcrest.Matchers.is;
  8. import static org.junit.Assert.assertThat;
  9. /**
  10. * @program: springboot
  11. * @description: 参数化测试
  12. * @author: Sid
  13. * @date: 2018-11-15 10:33
  14. * @since: 1.0
  15. **/
  16. //1.需要使用Parameterized运行器
  17. @RunWith(Parameterized.class)
  18. public class ParameterTest {
  19. // 2.声明变量存放预期值和测试数据
  20. private String firstName;
  21. private String lastName;
  22. //3.声明一个返回值 为Collection的公共静态方法,并使用@Parameters进行修饰
  23. @Parameterized.Parameters //
  24. public static List<Object[]> param() {
  25. // 两个测试用例
  26. return Arrays.asList( new Object[][]{{ "Sid", "Lee"}, { "Tom", "Cat"}});
  27. }
  28. //4.为测试类声明一个带有参数的公共构造函数,并在其中为之声明变量赋值
  29. public ParameterTest(String firstName, String lastName) {
  30. this.firstName = firstName;
  31. this.lastName = lastName;
  32. }
  33. // 5. 进行测试,发现它会将所有的测试用例测试一遍
  34. @Test
  35. public void test() {
  36. String name = firstName + " " + lastName;
  37. assertThat( "Sid Lee", is(name));
  38. }
  39. }

 

2.使用Theories入参

提供一组参数的排列组合值作为待测方法的输入参数。

使用Theories这个Runner的时候,待测方法可以拥有输入参数,而这在其它的Runner中的测试方法是不行的。


 
 
  1. package com.sid.controller;
  2. import org.junit.experimental.theories.DataPoint;
  3. import org.junit.experimental.theories.DataPoints;
  4. import org.junit.experimental.theories.Theories;
  5. import org.junit.experimental.theories.Theory;
  6. import org.junit.runner.RunWith;
  7. /**
  8. * @program: springboot
  9. * @description:
  10. * @author: Sid
  11. * @date: 2018-11-15 11:41
  12. * @since: 1.0
  13. **/
  14. @RunWith(Theories.class)
  15. public class TestTheories {
  16. @DataPoint
  17. public static String nameValue1 = "Sid";
  18. @DataPoint
  19. public static String nameValue2 = "Pencil";
  20. @DataPoint
  21. public static int ageValue1 = 27;
  22. @DataPoint
  23. public static int ageValue2 = 18;
  24. //也可以用这种方式提供参数
  25. // @DataPoints
  26. // public static String[] names = {"Sid", "Pencil"};
  27. // @DataPoints
  28. // public static int[] ages = {27, 18};
  29. @Theory
  30. public void testMethod(String name, int age){
  31. System.out.println(String.format( "%s's age is %s", name, age));
  32. }
  33. }

结果: 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值