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-封装通用的单元测试模板

单元测试模板可以满足如下需求:

  • 抽取公用的方法和注解,优化代码,实现代码复用,也方便维护
  • 多个单元测试类,一个启动入口,实现一键测试

接口测试的步骤

  1. 请求数据
  2. 构造请求
  3. 执行请求及判断请求结果
  4. 处理返回参数(本步骤可以没有)

备注:本项目的接口因为供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-项目单元测试(接口测试)的更多相关文章

  1. springmvc 项目单元测试

    对于web项目如果希望通过url来进行单元测试,但是启动服务器和建立http client 来进行测试非常麻烦,并且依赖网络环境.这样我们可以通过引入MockMvc进行测试. 一.引入jar包 < ...

  2. SpringBoot项目单元测试

    关于SpringBoot的单元测试,描述一下三种单元测试的方式. 1.约定 单元测试代码写在src/test/java目录下单元测试类命名为*Test,前缀为要测试的类名 2. 使用mock方式单元测 ...

  3. dubbo+maven多模块项目单元测试

    基本上就是记录各种报错的解决办法.基本上就是将散落在项目各个模块中的配置文件复制到测试模块中. 目录结构: ——src ——java ——test ——java ——DaoTest.java ——re ...

  4. django项目的接口测试

    基于Python的Django框架: 进行接口测试: 参见虫师的博客: 整理部分笔记:

  5. SSM项目 单元测试中 注入bean 空指针异常

    ##特别 由于准备春招,所以希望各位看客方便的话,能去github上面帮我Star一下项目https://github.com/Draymonders/Campus-Shop java.lang.Nu ...

  6. maven项目, 单元测试失败提示 Class not found datastorage........

    ---恢复内容开始--- 单元测试失败:  提示 Class not found datastorage........ 原因:   maven  环境变量问题,   eclipse 没有自动更新下载 ...

  7. springboot 项目单元测试

    项目结构如下 1 引入测试的 maven 依赖 <dependency> <groupId>org.springframework.boot</groupId> & ...

  8. 在Azure DevOps Server中运行基于Spring Boot和Consul的微服务项目单元测试

    1 概述 谈到微服务架构体系,绕不开服务发现这个功能.服务发现机制是简化微服务配置.实现容灾.水平扩缩容.提高运维效率的重要方式.在服务发现工具中,Consul在部署和使用方面与容器结合的天衣无缝,成 ...

  9. SpringBoot项目单元测试不经过过滤器问题

    SpringBoot使用MockMvc:https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-featu ...

随机推荐

  1. Markdown使用方法

    目录 Markdown 简明语法手册 1. 斜体和粗体 2. 分级标题 这是一个一级标题 这是一个二级标题 这是一个三级标题 3. 外链接 4. 无序列表 5. 有序列表 6. 文字引用 7. 行内代 ...

  2. Javascript 来判断数组的假值如 null false "" NaN

    Javascript 来判断数组的假值如 null false "" NaN function bouncer(arr) { arr = arr.filter(function(a ...

  3. SoundManager 2 / API Demo and Code Examples

    http://www.schillmania.com/projects/soundmanager2/

  4. Web GIS系统相关

    最近研究了百度 echarts 的一个很炫酷的示例: http://gallery.echartsjs.com/editor.html?c=xrJHCfsfE- 看了代码发现了很多不懂1东西,研究研究 ...

  5. ubuntu彻底卸载opencv

    说正事之前,先啰嗦两句背景,算是拿个小本本记下了. 我本打算下载opencv2.4.在github上找到源码,在Branch处选择切换到2.4,然后复制URL,在terminal里面使用git clo ...

  6. ROS下利用realsense采集RGBD图像合成点云

    摘要:在ROS kinetic下,利用realsense D435深度相机采集校准的RGBD图片,合成点云,在rviz中查看点云,最后保存成pcd文件. 一. 各种bug 代码编译成功后,打开rviz ...

  7. 【OpenStack】相关概念

    网络 network和subnet Service subnets: 创建network,subnet, instances 官方示例 Network components: Switches/ Ro ...

  8. centos7 源码安装redis

    安装3.x [root@node1 ~]# yum install wget gcc-c++ make [root@node1 ~]# wget http://download.redis.io/re ...

  9. 2017-2018-2 20165312 课下选做 MySort

    2017-2018-2 20165312 课下选做 MySort 题目描述 模拟实现Linux下Sort -t : -k 2的功能,参考 Sort的实现. import java.util.*; pu ...

  10. Keras处理已保存模型中的自定义层(或其他自定义对象)

    如果要加载的模型包含自定义层或其他自定义类或函数,则可以通过 custom_objects 参数将它们传递给加载机制: from keras.models import load_model # 假设 ...