一、背景描述

在版本开发中,时间段大致的划分为:需求,开发,测试;

  • 需求阶段:理解需求做好接口设计;
  • 开发阶段:完成功能开发和对接;
  • 测试上线:自测,提测,修复,上线;

实际上开发阶段两个核心的工作,开发和流程自测,自测的根本目的是为自己提前解决可能出现的问题;如果缺少自测和提测两个关键步骤,那么问题就会被传递给更多的用户,产生更多的资源消耗;

自测是于开发而言,提测是对专业的测试人员而言,如果尽可能在自测阶段就发现问题,并解决问题,那么一个问题就不会影响到团队协作上的更多人员,如果一个简单的问题上升到团队协作层面,很可能会导致问题本身被放大

工欲善其事必先利其器,开发如果要做好自测流程,学会使用工具提高效率是十分关键的,自测的关键在于发现问题和解决问题,所以选择好用和高效的工具可以极大的降低自测的时间消耗。

下面围绕几个自己开发过程中常用的测试工具和手段,做简单的总结,不在于对比方式的好坏,存在即合理,在不同场景中对合理手段的选择,快速解决问题才是根本目的

二、PostMan工具

PostMan很常用的接口测试工具,开发过程中快速测试接口,功能强大并且简单方便,不但可以单个接口测试,也可以对接口分块管理批量运行:

整体来说工具比较好用,适应于开发阶段的接口快速测试,或者在解决问题的过程中单个接口的测试,同时对测试参数有存储和记忆能力,这也是受欢迎的一大原因。

但是该工具不适应于复杂的流程化测试,例如需要根据上次接口的响应报文做分别处理,或者下次请求需要填充某个接口响应的数据。

三、Swagger文档

Swagger管理接口文档,是当下服务中很常用的组件,通过对接口和对象的简单注释,快速生成接口描述信息,并且可以对接口发送请求,协助调试,该文档在前后端联调中极大的提高效率。

接口文档的管理本身是一件麻烦事,接口通常会根据业务不断的调整,如果单独维护一份接口文档,需要付出很多时间成本,并且容易出问题,利用swagger就可以避免这个问题。

借助swagger注解标记对象

@TableName("jt_activity")
@ApiModel(value="活动PO对象", description="活动信息表【jt_activity】")
public class Activity { @ApiModelProperty(value = "主键ID")
@TableId(type = IdType.AUTO)
private Integer id; @ApiModelProperty(value = "活动主题")
private String activityTitle; @ApiModelProperty(value = "联系号码")
private String contactPhone; @ApiModelProperty(value = "1线上、2线下")
private Integer isOnline; @ApiModelProperty(value = "举办地址")
private String address; @ApiModelProperty(value = "主办单位")
private String organizer; @ApiModelProperty(value = "创建时间")
private Date createTime;
}

借助swagger注解标记接口

@Api(tags = "活动主体接口")
@RestController
public class ActivityWeb { @Resource
private ActivityService activityService ; @ApiOperation("新增活动")
@PostMapping("/activity")
public Integer save (@RequestBody Activity activity){
activityService.save(activity) ;
return activity.getId() ;
} @ApiOperation("主键查询")
@GetMapping("/activity/{id}")
public Activity getById (@PathVariable("id") Integer id){
return activityService.getById(id) ;
} @ApiOperation("修改活动")
@PutMapping("/activity")
public Boolean updateById (@RequestBody Activity activity){
return activityService.updateById(activity) ;
}
}

通常来说,基于swagger注解标记接口类和方法上的入参和关键返参对象即可,这样可以避免再单独维护接口文档。

Swagger接口文档在开发的过程中更多是扮演文档的角色,真正使用swagger去调试的接口也常是一些增删改查的简单接口,这个工具也同样不适应于复杂流程的测试。

四、TestRestTemplate类

SpringBoot测试包中集成的测试API,需要依赖测试包,可以访问控制层接口,非常方便的完成交互过程:

Jar包依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

使用案例

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ActivityTest01 {
protected static Logger logger = LoggerFactory.getLogger(ActivityTest01.class) ; @Resource
private TestRestTemplate restTemplate; private Activity activity = null ;
@Before
public void before (){
activity = restTemplate.getForObject("/activity/{id}", Activity.class,1);
logger.info("\n"+JSONUtil.toJsonPrettyStr(activity));
}
@Test
public void updateById (){
if (activity != null){
activity.setCreateTime(new Date());
activity.setOrganizer("One商家");
restTemplate.put("/activity",activity);
}
}
@After
public void after (){
activity = restTemplate.getForObject("/activity/{id}", Activity.class,1);
logger.info("\n"+JSONUtil.toJsonPrettyStr(activity));
activity = null ;
}
}

在TestRestTemplate源码中可以发现,基于RestTemplate做封装,很多功能的实现都是调用RestTemplate方法。

用写代码的方式去实现接口测试,灵活度非常高,可以根据流程做定制开发,很适应于中等复杂的场景测试,这里为什么这样描述,下面对比Http请求再细说。

五、Http请求模式

通过模拟接口的Http请求实现的方式,目前来说个人感觉灵活的最高的方式,先看简单的案例:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class ActivityTest03 {
protected static Logger logger = LoggerFactory.getLogger(ActivityTest03.class) ;
protected static String REQ_URL = "服务地址+端口"; @Test
public void testHttp (){
// 查询
String getRes = HttpUtil.get(REQ_URL+"activity/1");
logger.info("\n {} ",JSONUtil.toJsonPrettyStr(getRes));
Activity activity = JSONUtil.toBean(getRes, Activity.class) ;
// 新增
activity.setId(null);
activity.setOrganizer("Http商家");
String saveRes = HttpUtil.post(REQ_URL+"/activity",JSONUtil.toJsonStr(activity));
logger.info("\n {} ",saveRes);
// 更新
activity.setId(Integer.parseInt(saveRes));
activity.setOrganizer("Put商家");
String putRes = HttpRequest.put(REQ_URL+"/activity")
.body(JSONUtil.toJsonStr(activity)).execute().body();
logger.info("\n {} ",putRes);
}
}

这种方式对于复杂的业务流程来说非常好用,当然这里不排除个人习惯,在测试复杂流程的时候,一个简单方案:

  • 用户信息:模拟http中token数据;
  • 业务流程:通过数据获取包装参数模型;
  • 独立服务管理,模拟并发场景;
  • 根据执行过程生成分析数据结果;

对于复杂业务流程的测试,每个节点的模拟都具有一定的难度,通常在完整的流程中涉及到的服务和库表都是多个,并且请求链路复杂,基于一个灵活的自动化流程,去测试完整的链路,可以对效率有极大的提升。

六、Service层测试

针对服务层的测试手段,其本意在于业务实现的逻辑测试:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ActivityTest04 {
protected static Logger logger = LoggerFactory.getLogger(ActivityTest04.class) ; @Autowired
private ActivityService activityService ; @Test
public void testService (){
// 查询
Activity activity = activityService.getById(1) ;
// 新增
activity.setId(null);
activityService.save(activity) ;
// 修改
activity.setOrganizer("Ser商家");
activityService.updateById(activity) ;
// 删除
activityService.removeById(activity.getId()) ;
}
}

该测试在实际的开发过程也并不常用,偶尔在于某个业务方法实现难度很大,用来针对性测试。

七、MockMvc方式

MockMvc同样是SpringBoot集成测试包提供的测试方式,通过对象的模拟,验证接口是否符合预期:

@AutoConfigureMockMvc
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class ActivityTest02 {
protected static Logger logger = LoggerFactory.getLogger(ActivityTest02.class) ;
@Resource
private MockMvc mockMvc ; private Activity activity = null ; @Before
public void before () throws Exception {
ResultActions resultAction = mockMvc.perform(MockMvcRequestBuilders.get("/activity/{id}",1)) ;
MvcResult mvcResult = resultAction.andReturn() ;
String result = mvcResult.getResponse().getContentAsString();
activity = JSONUtil.toBean(result,Activity.class) ;
} @Test
public void updateById () throws Exception {
activity.setId(null);
activity.setCreateTime(new Date());
activity.setOrganizer("One商家");
ResultActions resultAction = mockMvc.perform(MockMvcRequestBuilders.post("/activity")
.contentType(MediaType.APPLICATION_JSON)
.content(JSONUtil.toJsonStr(activity))) ;
MvcResult mvcResult = resultAction.andReturn() ;
String result = mvcResult.getResponse().getContentAsString();
activity.setId(Integer.parseInt(result));
logger.info("result : {} ",result);
} @After
public void after () throws Exception {
activity.setCreateTime(new Date());
activity.setOrganizer("Update商家");
ResultActions resultAction = mockMvc.perform(MockMvcRequestBuilders.put("/activity")
.contentType(MediaType.APPLICATION_JSON)
.content(JSONUtil.toJsonStr(activity))) ;
MvcResult mvcResult = resultAction.andReturn() ;
String result = mvcResult.getResponse().getContentAsString();
logger.info("result : {} ",result);
}
}

对于这种Mock类型的测试,非常专业,通常个人使用极少,暂时没有Get到其精髓思想。

八、Mockito测试

Mock属于非常专业和标准的测试手段,需要依赖powermock包:

<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<scope>test</scope>
</dependency>

简单使用案例:

@RunWith(PowerMockRunner.class)
@SpringBootTest
public class ActivityTest05 { @Test
public void testMock (){
Set mockSet = PowerMockito.mock(Set.class);
PowerMockito.when(mockSet.size()).thenReturn(10);
int actual = mockSet.size();
int expected = 15 ;
Assert.assertEquals("返回值不符合预期",expected, actual);
} @Test
public void testTitle (){
String expectTitle = "Mock主题" ;
Activity activity = PowerMockito.mock(Activity.class);
PowerMockito.when(activity.getMockTitle()).thenReturn(expectTitle);
String actualTitle = activity.getMockTitle();
Assert.assertNotEquals("主题相符", expectTitle, actualTitle);
}
}

可以通过Mock方式,快速模拟出复杂的对象结构,以便构建测试方法,由于使用很少,同样个人暂时没Get到点。

九、源代码地址

GitHub·地址
https://github.com/cicadasmile/middle-ware-parent
GitEE·地址
https://gitee.com/cicadasmile/middle-ware-parent

阅读标签

Java基础】【设计模式】【结构与算法】【Linux系统】【数据库

分布式架构】【微服务】【大数据组件】【SpringBoot进阶】【Spring&Boot基础

数据分析】【技术导图】【 职场

SpringBoot2 集成测试组件,七种测试手段对比的更多相关文章

  1. <转>七种测试驱动模式

    本文转载自微信公众号:中国软件测试联盟 在进行软件测试时,我们都需要一个出发点,从哪里开始分析?测试设计是基于什么?简单说,就是什么驱动测试工作的进行? 基于对软件工程.产品质量和测试的理解,归纳出以 ...

  2. Mysql表的七种引擎类型,InnoDB和MyISAM引擎对比区别总结

    InnoDB和MyISAM区别总结 我用MySQL的时候用的是Navicat for MySQL(Navicat for mysql v9.0.15注册码生成器)操作库.表操作的,默认的表就是Inno ...

  3. Vue 定义组件模板的七种方式(一般用单文件组件更好)

    在 Vue 中定义一个组件模板,至少有七种不同的方式(或许还有其它我不知道的方式): 字符串 模板字面量 x-template 内联模板 render 函数 JSF 单文件组件 在这篇文章中,我将通过 ...

  4. 让 Python 代码更易维护的七种武器——代码风格(pylint、Flake8、Isort、Autopep8、Yapf、Black)测试覆盖率(Coverage)CI(JK)

    让 Python 代码更易维护的七种武器 2018/09/29 · 基础知识 · 武器 原文出处: Jeff Triplett   译文出处:linux中国-Hank Chow    检查你的代码的质 ...

  5. Linux就这个范儿 第15章 七种武器 linux 同步IO: sync、fsync与fdatasync Linux中的内存大页面huge page/large page David Cutler Linux读写内存数据的三种方式

    Linux就这个范儿 第15章 七种武器  linux 同步IO: sync.fsync与fdatasync   Linux中的内存大页面huge page/large page  David Cut ...

  6. PHP程序猿必备的七种武器

    作为一个程序猿(又或者是程序媛),出来闯荡江湖,没有几种必杀技在手,那是肯定无法赢得江湖名声的,除了必杀技之外,武器也是很重要的,但是一把青钢剑,肯定是无法赢得万千少男少女的欢心的.就连小李飞刀,人家 ...

  7. 探讨SQL Server并发处理存在就更新七种解决方案

    前言 本节我们来讲讲并发中最常见的情况存在即更新,在并发中若未存在行记录则插入,此时未处理好极容易出现插入重复键情况,本文我们来介绍对并发中存在就更新行记录的七种方案并且我们来综合分析最合适的解决方案 ...

  8. Hanlp等七种优秀的开源中文分词库推荐

    Hanlp等七种优秀的开源中文分词库推荐 中文分词是中文文本处理的基础步骤,也是中文人机自然语言交互的基础模块.由于中文句子中没有词的界限,因此在进行中文自然语言处理时,通常需要先进行分词. 纵观整个 ...

  9. 快速开发平台分享-UCML快速开发七种武器

    传统的快速开发平台强调的是组件重用.构件重用,主要解决功能重用层面,一般提供了软件开发最常用的功能:表单设计.BPM(业务流程管理).报表.组织机构及权限等功能.但只有功能重用,没有过程重用,要么只能 ...

随机推荐

  1. Tomcat集群 Nginx负载均衡 shell脚本实时监控Nginx

    第一步,安装Tomcat 系统环境:Centos7 第1步:下载tomcat安装包 tomcat官网:https://tomcat.apache.org/ 第2步:安装包上传至linux中 第3步:下 ...

  2. Python:读写文件(I/O) | 组织文件

    1. I/O 概述  程序与用户交互涉及到程序的输入输出(I/O) 一种类型是字符串,通过input() 和 print() 函数以及数据类型转换类函数如(int()),实现数据的输入输出. 另一种类 ...

  3. JDBC_05_ResorceBundle(资源绑定器) 绑定配置文件

    ResorceBundle(资源绑定器) 绑定配置文件 jdbc.proprtise 需要在src目录下新建一个文件夹然后将jdbc.proprtise放在文件中然后右键该文件夹选择 Rebuild ...

  4. 代码安全丨第六期:XPath注入漏洞样例

    1.什么是XPath注入漏洞? XPath是一种用来在内存中导航整个XML树的语言,它使用路径表达式来选取XML文档中的节点或者节点集. XPath注入是指程序使用外部输入动态构造用于从XML数据库检 ...

  5. 绕过阿里云waf进行mysql limit注入证明

    朋友发了我一个站点,来看看吧,是limit注入,不太常见.搞一搞吧. POST /Member/CompanyApply/lists HTTP/1.1 Host: * Content-Length: ...

  6. OO博客总结——OO落下帷幕

    OO博客总结--OO落下帷幕 凡此过往,皆为序章. 不知不觉OO课程即将落下帷幕,一路坎坎坷坷磕磕绊绊,可算是要结束了,心里终于松了一口气,也有小小的不甘和遗憾.凡此过往,皆为序章.特殊的线上OO课程 ...

  7. SpringCloud(五)GateWay网关

    Config 分布式配置中心 概述 微服务意味着要将单体应用中的业务拆分成个个子服务,每个服务的粒度相对较小因此系统中会出现大量的服务 由于每个服务都需要必要的配置信息才能运行,所以一套集中式的.动态 ...

  8. hdu3329 二分+搜索

    题意:       给你一个岛,然后岛的外侧开始涨水(内侧不涨只有外侧,也就是里面的0永远是0),问最少涨水多少才能把岛分成两个或者两个以上. 思路:       可以二分枚举水的高度(数据不大估计暴 ...

  9. hdu1686 最大匹配次数 KMP

    题意:      给你两个串,问你串a在串b中出现了多少次. 思路:       直接匹配,KMP时匹配到匹配串的最后一个的时候不用跳出,直接匹配就行了,最后一个'/0'不会和目标串匹配,所以经过ne ...

  10. PAT 乙级 -- 1008 -- 数组元素循环右移问题

    题目简述 一个数组A中存有N(N>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(M>=0)个位置,即将A中的数据由(A0 A1--AN-1)变换为(AN-M -- AN ...