Springboot08-项目单元测试(接口测试)
Springboot学习08-项目单元测试(接口测试)
前言
1-本文重点在于源码层面,分析Springboot单元测试的使用,对于其中的注解、方法等,不会仔细分析;
2-本文项目实例相关配置:Java-1.8; Springboot-1.5.12.RELEASE,使用的是Intellij
正文
1- JUnitGenerator V2.0 单元测试代码自动生成插件的使用
因为插件的安装和使用,比较简单,见参考资料-1,或自行百度;这里不再赘述;
注意:JUnitGenerator主要是可以针对需要测试的类,在test目录下快速生成对应的测试类,而测试的具体实现还是要手动处理;
2-最简单的单元测试,源码如下:
package com.hs.web.controller.system.login;
import net.sf.json.JSONObject; @RunWith(SpringRunner.class)
@SpringBootTest(classes= FrameworkApplication.class)
public class LoginControllerTest { private MockMvc mvc; @Autowired
private WebApplicationContext context; @Before
public void setUp() throws Exception {
mvc = MockMvcBuilders.webAppContextSetup(context).build();
}
@Test
public void login() throws Exception{
//1-封装请求参数
Map<String, String> paramMap = new HashMap<>();
paramMap.put("openid", "tangyujie");
JSONObject jsonObject = JSONObject.fromObject(paramMap);
//2-构建请求
RequestBuilder builder = MockMvcRequestBuilders.post("/api/shop/login").content(jsonObject.toString()).
accept(MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_JSON);
//3-执行请求
mvc.perform(builder)
.andExpect(status().isOk())
.andExpect(jsonPath("code").value(200))
.andDo(MockMvcResultHandlers.print());
}
@After
public void after(){ }
}
如果只测试一个接口,或者只测试一个类,那么上面的方法基本上已经可以满足需求,但是针对上百个类或方法的情况,则会出现大量的代码冗余,并且还需要手动启动每一个测试类,这明显是不可取的;
所以,在上述简单的单元测试方法上,进行封装
3-封装通用的单元测试模板
单元测试模板可以满足如下需求:
- 抽取公用的方法和注解,优化代码,实现代码复用,也方便维护
- 多个单元测试类,一个启动入口,实现一键测试
接口测试的步骤
- 请求数据
- 构造请求
- 执行请求及判断请求结果
- 处理返回参数(本步骤可以没有)
备注:本项目的接口因为供App使用,(除了登录接口)其他都是要传token(跟在UTL?后面)
源码如下
测试模板目录

BaseTest抽象类,用于封装通用方法
package com.hs.api.base;
import net.sf.json.JSONObject;
public abstract class BaseTest {
//1-1-构建post请求
protected RequestBuilder getPostBuilder(String url, JSONObject jsonObject){
RequestBuilder builder = MockMvcRequestBuilders
.post(url)
.content(jsonObject.toString())
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON);
return builder;
}
//1-2-构建get请求
protected RequestBuilder getGetBuilder(String url){
RequestBuilder builder = MockMvcRequestBuilders
.get(url)
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON);
return builder;
}
//2-执行请求
protected MvcResult performMVC(MockMvc mvc, RequestBuilder bulider ){
try {
MvcResult mvcResult = mvc.perform(bulider)
.andExpect(status().isOk())
.andExpect(jsonPath("code").value(200))
//.andDo(MockMvcResultHandlers.print())
.andReturn();
return mvcResult;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
BaseControllerTest类,继承 BaseTest抽象类,且是所有单元测试类的父类, 使用了@RunWith、@SpringBootTest等类注解,并且实现了通用的@Before和@After方法,以及登录接口的具体实现,主要是从普通的单元测试类中提取出公有的因素
package com.hs.api.base;
import net.sf.json.JSONObject;
//所有单元测试类的基类
@RunWith(SpringRunner.class)
@SpringBootTest(classes= FrameworkApplication.class)
@WebAppConfiguration
public abstract class BaseControllerTest extends BaseTest { @Autowired
protected WebApplicationContext context; protected MockMvc mvc ;
protected static String shopToken = null;//apptoken @Before
protected void setUp() throws Exception {
System.out.println("controller test is starting");
mvc = MockMvcBuilders.webAppContextSetup(context).build();
if(shopToken == null){
System.out.println("获取shoptoken");
shopToken = shopLogin();
}
}
@After
protected void tearDown(){
System.out.println("controller test is over");
} //1-App登录操作
protected String shopLogin() {
//1-请求数据
String url = "/api/shop/login";
LoginReq loginReq = new LoginReq("tangyujie");
JSONObject content = JSONObject.fromObject(loginReq);
//2-构造请求
RequestBuilder postBuilder = getPostBuilder(url, content);
try {
//3-执行请求-及判断请求结果
MvcResult mvcResult = performMVC(mvc, postBuilder);
//4-c处理返回参数,获取shopToken
String contentAsString = mvcResult.getResponse().getContentAsString();
//System.out.println("contentAsString=== " + contentAsString);
JSONObject jsonObject = JSONObject.fromObject(contentAsString);
Map<String,Class<?>> classMap = new HashMap<String,Class<?>>();
classMap.put("data", LoginRes.class);
TestShopLoginRes entity = (TestShopLoginRes)JSONObject.toBean(jsonObject,TestShopLoginRes.class,classMap);
//System.out.println("entity: " + entity);
return entity .getData().getShopToken();
} catch (Exception e) {
e.printStackTrace();
return null;
}
} }
ApiShopLoginControllerTest类,登录的接口的测试类,继承BaseControllerTest类;本类包含一个POST接口实例
package com.hs.api.shopapp.controller;
public class ApiShopLoginControllerTest extends BaseControllerTest{
//POST请求示例
//1-登录
@Test
public void loginOrRegister() {
shopLogin();
}
}
ApiShopMemberControllerTest类,用户接口的测试类,继承BaseControllerTest类;本类包含一个GET接口实例
package com.hs.api.shopapp.controller;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; public class ApiShopMemberControllerTest extends BaseControllerTest{ //GET请求示例
@Test
public void getMemberShopInfo() {
//1-请求参数
System.out.println("shopToken == " + shopToken);
String url = "/api/shop/member/detail?shopToken=" + shopToken;
//2-构建请求
RequestBuilder getBuilder = getGetBuilder(url);
try {
//3-执行请求
MvcResult mvcResult = performMVC(mvc, getBuilder);
System.out.println("getMemberShopInfo mvcResult: " + mvcResult);
} catch (Exception e) {
e.printStackTrace();
}
} }
TestSuits类,本类没有具体的方法,唯一的作用是作为启动入口,测试全部测试类的方法
package com.hs.api; import org.junit.runner.RunWith;
import org.junit.runners.Suite; //单元测试总入口,在@Suite.SuiteClasses里面添加需要测试的测试类
@RunWith(Suite.class)
@Suite.SuiteClasses({
ApiShopLoginControllerTest.class,
ApiShopMemberControllerTest.class
})
public class TestSuits {
}
以下是模板用到的实体类POJO,主要是用户封装请求参数或返回参数,注意实体类和JSON字符串之间的转换
//请求参数实体类
public class LoginReq {
private String openid;//openid public LoginReq() {
} //省略geter和setter方法
} //返回参数实体父类
package com.hs.api.common; public class TestResponseEntity { public int code;
public String message; public TestResponseEntity() {
} //省略geter和setter方法
}
//登录接口返回参数实体类(两个,相互嵌套关系) public class TestShopLoginRes extends TestResponseEntity {
private LoginRes data; public TestShopLoginRes() {
} public TestShopLoginRes(LoginRes data) {
this.data = data;
} //省略geter和setter方法 @Override
public String toString() {
return "TestShopLoginRes{" +
"data=" + data +
'}';
}
} public class LoginRes { private Long shopId;//
private int mobileExistFlag;//手机号是否存在
private String shopToken;//
private int vipFlag;//是否是会员 public LoginRes() {
} //省略geter和setter方法 @Override
public String toString() {
return "LoginRes{" +
"shopId=" + shopId +
", mobileExistFlag=" + mobileExistFlag +
", shopToken='" + shopToken + '\'' +
", vipFlag=" + vipFlag +
'}';
}
}
以下是实例中测试的实际接口类
//登录接口类
@RestController
@RequestMapping(value="/api/shop/login")
public class ApiShopLoginController extends ApiShopBaseController { //1-登陆或注册
@RequestMapping(value="",method = RequestMethod.POST,produces = {JSON_UTF8})
public String loginOrRegister(@RequestBody LoginReq loginReqt){
//省略业务
}
} //用户接口类 @RestController
@RequestMapping(value="/api/shop/member")
public class ApiShopMemberController extends ApiShopBaseController { //1-店主基本信息
@RequestMapping(value = { "/detail" }, method={RequestMethod.GET},produces = {JSON_UTF8})
public String getMemberShopInfo() throws ServerSqlErrorException {
//省略业务
}
}
参考文献:
1-JUnitGenerator使用方法:http://www.pianshen.com/article/516640707/
2-测试用例整合:https://blog.csdn.net/weixin_39800144/article/details/79241620
3-返回参数处理:https://blog.csdn.net/qq_16513911/article/details/83018027
Springboot08-项目单元测试(接口测试)的更多相关文章
- springmvc 项目单元测试
对于web项目如果希望通过url来进行单元测试,但是启动服务器和建立http client 来进行测试非常麻烦,并且依赖网络环境.这样我们可以通过引入MockMvc进行测试. 一.引入jar包 < ...
- SpringBoot项目单元测试
关于SpringBoot的单元测试,描述一下三种单元测试的方式. 1.约定 单元测试代码写在src/test/java目录下单元测试类命名为*Test,前缀为要测试的类名 2. 使用mock方式单元测 ...
- dubbo+maven多模块项目单元测试
基本上就是记录各种报错的解决办法.基本上就是将散落在项目各个模块中的配置文件复制到测试模块中. 目录结构: ——src ——java ——test ——java ——DaoTest.java ——re ...
- django项目的接口测试
基于Python的Django框架: 进行接口测试: 参见虫师的博客: 整理部分笔记:
- SSM项目 单元测试中 注入bean 空指针异常
##特别 由于准备春招,所以希望各位看客方便的话,能去github上面帮我Star一下项目https://github.com/Draymonders/Campus-Shop java.lang.Nu ...
- maven项目, 单元测试失败提示 Class not found datastorage........
---恢复内容开始--- 单元测试失败: 提示 Class not found datastorage........ 原因: maven 环境变量问题, eclipse 没有自动更新下载 ...
- springboot 项目单元测试
项目结构如下 1 引入测试的 maven 依赖 <dependency> <groupId>org.springframework.boot</groupId> & ...
- 在Azure DevOps Server中运行基于Spring Boot和Consul的微服务项目单元测试
1 概述 谈到微服务架构体系,绕不开服务发现这个功能.服务发现机制是简化微服务配置.实现容灾.水平扩缩容.提高运维效率的重要方式.在服务发现工具中,Consul在部署和使用方面与容器结合的天衣无缝,成 ...
- SpringBoot项目单元测试不经过过滤器问题
SpringBoot使用MockMvc:https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-featu ...
随机推荐
- CSVN配置自动备份策略
在浏览器中登录CSVN管理页面,登录地址就是ip:3343,版本库->backup schedule ,选择type of job(备份类型),when to run(备份频率和时间),numb ...
- Scala环境(集成idea)
1 语言介绍 他已经出生15年了,就像明星一样,谁都不可能一开始就人气爆棚粉丝无数,得慢慢混. 据说这家伙已经威胁到了Java的地位,我当时也是被这句话惊到,才毅然决然的认识了他.目前也正在努力学习中 ...
- 第三章 JQuery: HelloWorld--常见方法--css--选择器--筛选器--属性--效果--事件--数组操作--字符串操作--对象转换
1.jQuery简介 为了简化JavaScript 的开发, 一些JavsScript 库诞生了. JavaScript库封装了很多预定义的对象和实用函数.能帮助使用者建立有高难度交互的页面, 并且兼 ...
- 数组中只出现一次的数字(java实现)
问题描述 一个整型数组里除了两个数字之外,其他的数字都出现了偶数次.请写程序找出这两个只出现一次的数字. 解题思路 如果数组中只有一个数字出现奇数次,则将数组中所有的数字做异或可得该数字. 数组中有两 ...
- access十万级数据分页
最近的一个项目采用winform+access,但后来发现客户那边的数据量比较大,有数十万条数据.用sql语句进行分页,每次翻页加载都需要8秒钟左右,实在难以忍受. 后来百度了一下,发现一篇文章我的A ...
- centos7.6+samba+设置可读可写不可删权限
samba原文 https://www.cnblogs.com/muscleape/p/6385583.html 设置可读可写不可删权限原文: https://blog.51cto.com/guanh ...
- 在pycharm_2018.2版本中开启Flask的debug的方法 (不要用命令:python **.py启动)
断点后,先ctl+c关闭控制台程序,再点击debuger调试 问题描述:在pycharm_2018.2版本中,我明确开启了debug,代码如下所示: from flask import Flask a ...
- 向量的卷积(convolution)运算
一.向量的卷积运算 给定两个n维向量α=(a0, a1, ..., an-1)T,β=(b0, b1, ..., bn-1)T,则α与β的卷积运算定义为: α*β=(c0, c1, ..., c2n- ...
- (dev mode) install CONSUL on ubuntu
WSL: V18.04.1 1. install $sudo apt-get update$sudo apt-get install consul wsl1017@DESKTOP-14G6K9S:~$ ...
- 系统变量之System.getenv()和System.getProperty()
Java提供了System类的静态方法getenv()和getProperty()用于返回系统相关的变量与属性,getenv方法返回的变量大多于系统相关,getProperty方法返回的变量大多与ja ...