Java单元测试Mock框架Mockito入门介绍

本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 鸡尾酒 Mockito是Java的单元测试Mock框架。它的logo是一杯古巴最著名的鸡尾酒Mojito,Mojito鸡尾酒,源自古巴的哈瓦那,带有浓厚的加勒比海风情。并不浓烈,但是喝一杯下去,脸上会泛起红晕,象少女的羞涩。味道很清新,有一点青涩、有点甜蜜。 Stub & Mock Stub和Mock是Test Double类型中的2种。Test Double一共有5种类型,Dummy,Stub,Spy,Mock,Fake。 Test Double是测试复制品,用来统称模拟真实对象的假对象。因使用场景有略微不同,而有这5种类型。 Dummy,通常只用来填充参数列表。有可能是null对象引用,或Object类实例等。 Fake,是简化版的实现,比如基于内存实现的数据库,不会真的去做数据库操作,用简单的HashMap来存放数据。 Stub,Stub用来替代SUT(System Under Test)依赖的组件,但是只模拟一个外部依赖,不做断言。 Spy,介于Stub和Mock之间。如果真实对象没有被打桩,当调用Spy对象时,真实对象也会被调用。 Mock,可以理解为Stub+Verification,既模拟外部依赖,也会定义预期结果。 看一个实例,发送邮件, public interface MailService { public void send(Message msg); } 先写个Stub, public class MailServiceStub implements MailService { private List<Message> messages = new ArrayList<Message>(); public void send(Message msg) { messages.add(msg); } public int numberSent() { return messages.size(); } } 实现Stub的状态验证, class OrderStateTester… public void testOrderSendsMailIfUnfilled() { Order order = new Order(TALISKER, 51); MailServiceStub mailer = new MailServiceStub(); order.setMailer(mailer); order.fill(warehouse); assertEquals(1, mailer.numberSent()); } 只做了简单的测试,断言发出了1封邮件。没有测试是否发送给了对的收件人,或者邮件正文是否正确。不过不影响跟Mock比较。 ...

JMeter四种参数化方式

JMeter参数化是指把固定的数据动态化,这样更贴合实际的模拟用户请求,比如模拟多个不同账号。JMeter一共有四种参数化方式,分别是:

Allure测试报告完整学习笔记

本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 目录 简介 安装Allure Allure测试报告的结构 Java TestNG集成Allure Report Python Pytest集成Allure Report 简介 假如你想让测试报告变得漂亮一点,那你一定会在搜索引擎中找到Allure测试报告的。Allure官方给出了个在线网站,访问以下链接就能一睹为快: https://demo.qameta.io/allure/ 可以在左下角切换为中文报告: 如此好看的测试报告,哪个老板不喜欢呢? 安装Allure 1.在GitHub releases: https://github.com/allure-framework/allure2/releases 或者Maven Central: https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/ 下载安装包并解压。 2.找到bin目录,Windows使用allure.bat,Unix使用allure: 3.为了后续方便使用,可以把bin完整路径添加到系统环境变量PATH中,然后在命令行直接输入allure命令。 官方也给出了通过Linux的ppa、Mac的brew、Windows的scoop的安装方式,不过对于咱们老百姓来说,不如手动下载包来安装实在。 安装后就可以检查是否安装成功了: $ allure --version 2.17.2 因为Allure是用Java写的,所以如果无法运行,那么要检查下有没有安装Java。 Allure测试报告的结构 Overview Categories Suites Graphs Timeline Behaviors Packages Java TestNG集成Allure Report 集成 在Maven的pom.xml中添加: <properties> <aspectj.version>1.8.10</aspectj.version> </properties> <dependencies> <dependency> <groupId>io.qameta.allure</groupId> <artifactId>allure-testng</artifactId> <version>LAST_VERSION</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.20</version> <configuration> <argLine> -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar" </argLine> </configuration> <dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectj.version}</version> </dependency> </dependencies> </plugin> </plugins> </build> 然后执行命令: ...

JMeter关联陌生又熟悉

本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 JMeter关联是什么 JMeter关联,这几个字看着可能会有点陌生,实际上却是工作中经常会做的一件事情,尤其是接口自动化,它指的是把一个接口的响应作为另一个接口的参数,从而把接口关联起来。 JMeter关联是通过后置处理器来实现的,本文将介绍两个主流提取器:正则表达式提取器和JSON JMESPath提取器。 正则表达式提取器 Name 最好有业务含义的名称。 Comments 可以为空的注释。 Apply to 匹配范围。 Main sample and sub-samples 匹配当前父取样器及其子取样器。 Main sample only 仅匹配当前父取样器。 Sub-samples only 仅匹配子取样器。 JMeter Variable Name to use 匹配JMeter变量。 Field to check 匹配响应的字段,共七个选项。 Body:主体,最常用。 Body(unescaped) :替换了所有的html转义符的响应主体内容,注意html转义符处理时不考虑上下文,因此可能有不正确的转换,不太建议使用。 Body as a Document:从不同类型的文件中提取文本,注意这个选项比较影响性能。 Response Headers:响应Headers。 Request Headers:请求Headers。 URL:请求URL。 Response Code:响应代码,比如200、404返回码。 Response Message:响应信息,比如“成功”、“OK”字样。 Name of created variable 创建的变量名,比如变量名为token,通过${token}进行访问。 Regular Expression 正则表达式。 正则表达式可阅读这篇文章进一步了解:https://dongfanger.gitee.io/blog/未分类/001-5分钟轻松学正则表达式.html Template($i$ where i is capturing group number, starts at 1) 用$$引用起来,如果在正则表达式中有多个正则表达式(多个括号括起来的),则可以是$1$、$2$等等,$1$指第一个模板,$2$指第二个模板,依次类推,$0$指全文匹配,$1$$2$指同时取第一个和第二个模板。 ...

JUnit5依赖注入与测试接口

本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 依赖注入 以前的JUnit的类构造方法和测试方法都是不能有参数的,JUnit Jupiter有一个颠覆性的改进,就是允许它们有入参,这样就能做依赖注入了。 如果你对pytest的fixture有了解的话,就知道这个技术是多么的强大。 ParameterResolver是一个接口类,类构造方法和测试方法在运行时,必须由被注册的ParameterResolver进行解析。JUnit Jupiter有三个自动注册的内置解析器: TestInfoParameterResolver 参数类型为TestInfo RepetitionInfoParameterResolver 参数类型为RepetitionInfo TestReporterParameterResolver 参数类型为TestReporter TestInfo TestInfo包含the display name, the test class, the test method, and associated tags等信息。 示例: import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; @DisplayName("TestInfo Demo") class TestInfoDemo { TestInfoDemo(TestInfo testInfo) { assertEquals("TestInfo Demo", testInfo.getDisplayName()); } @BeforeEach void init(TestInfo testInfo) { String displayName = testInfo.getDisplayName(); assertTrue(displayName.equals("TEST 1") || displayName.equals("test2()")); } @Test @DisplayName("TEST 1") @Tag("my-tag") void test1(TestInfo testInfo) { assertEquals("TEST 1", testInfo.getDisplayName()); assertTrue(testInfo.getTags().contains("my-tag")); } @Test void test2() { } } RepetitionInfo ...

JMeter100个线程竟然只模拟出1个并发

线程组编辑区如下:

JUnit5参数化测试的几种方式

参数化测试一直是津津乐道的话题,我们都知道JMeter有四种参数化方式:用户自定义变量、用户参数、CSV文件、函数助手,那么JUnit5有哪些参数化测试的方式呢?

老板给我安排了个测试环境治理的活

本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 测试环境困局 测试环境治理专项是在我入职2个月接手的活,用“烂摊子”来形容一点也不为过。年久失修,需求基本没有在测试环境使用,想用也有很多问题。人员缺乏信心,之前负责测试环境的同学抱怨极多,外部推不动,内部又没有技术能力支撑,负能量已经蔓延到整个团队。当然,我也是其中一员,这事确实难搞。在技术部测试环境平台化的大方向下,需要每个组出一个接口人来牵头,考虑到我以前写过测试平台,乱七八糟的事都整过,老板就指定了我。 What,测试环境是什么? 测试环境是一套能够支撑业务系统运行的环境,是相对于预发环境和生产环境来说完全隔离的环境。测试环境=应用+数据+配置+依赖服务。应用包含系统应用和中间件等,数据就是测试物料,配置针对测试环境应该有单独的一套,依赖服务要跟外部联调好以后整个环境才是可用的。测试环境治理就是通过内部搭建和外部联调,保障业务系统能够在完全隔离的环境中运行。 Why,为什么要做测试环境? 测试环境是为了隔离。如果只有一套生产环境,那么开发、测试、上线等活动,可能会对线上系统稳定性造成影响,可能会污染线上用户数据,可能引起客户投诉甚至资产损失,所以需要有一套完全隔离的测试环境。 Who,谁来负责测试环境? 每个测试人员都需要具备测试环境搭建能力。当然可以推动运维或研发来搭建测试环境,但是测试人员需要具备搭建能力,能够自主编译,构建,部署,遇到问题能够根据日志做初步定位,将问题抛出推动研发或外部依赖方解决。 When,什么时间做测试环境? 测试环境治理需要前置到研发自测阶段。在实践过程中,测试同学暴露出来最多的问题是,没有时间投入到测试环境搭建中,一方面是缺乏动力,不肯迈出艰难的第一步,另一方面也是跟项目节奏有关,研发就算用测试环境自测,也会在预发联调好以后再提测,到测试手上时,已经有可用的预发环境了,就不会再去用测试环境。“项目时间紧,测试环境不好用,直接用预发测吧”,顺理成章的就成为了很合理的借口。所以需要从提测,前置到,研发自测,做测试环境治理: Where,从哪里入手测试环境? 测试环境治理需要从上往下才能推动,先有文化,才有行动。假如只有某个部门想做测试环境治理,外部依赖基本上是推不动的,一个人呐喊得再愤怒其他人也可能无动于衷。所以得先把测试环境治理这件事,跟老板沟通,从高层入手,把它定义为一项政治任务,从上往下层层递进。 How,怎么做测试环境? 工欲善其事,必先利其器,公司的基建比较完善,给测试人员搭建测试环境降低了很大难度。设想一下,假如只能折腾Docker和K8S,那可能需要专门的运维才能搞得定环境,对测试来说门槛就会比较高了,除了少数技术能力强的,其他同学基本没有什么可操作性。测试环境平台化就是武器。公司有个部署平台叫做JDOS,日常运维都是在这上面操作,没有运维人员,环境全靠开发人员和测试人员自己整。JDOS已经是页面化操作了,但它对测试环境没有特殊的应用场景,是个大而全的平台,所以二级部门开了一个测试环境平台,Env,“一款全流程自动化测试环境搭建的利器”。 Env的核心思想是1+N。1代表稳定分组(分组≈Pod),搭建稳定分组需要经过创建系统,创建应用,创建集群,申请机器,代码编译构建,部署镜像,修改配置等操作,需要选取master稳定版本,这样才能对外提供稳定服务。N是克隆1产生的多个分组,相互隔离,能让开发同学复用测试搭建好的环境,完成冒烟自测等过程;也能在多业务联调测试时,通过平台快速搭建一套全链路测试环境。 Env提供了环境监控的功能。对于搭建好的稳定环境,它可以每天监控机器是否可用,服务是否正常,镜像是否老旧,等等等,让你及时维护环境,保障稳定性。 Env提供了一键搭建的功能。新克隆的环境,只要点一下“一键搭建”,就会基于稳定分组,自动化搭建一套新环境,大大节约了时间成本。 Env提供了拓扑画图的功能。将多个应用拖到一张拓扑图里面,根据依赖关系连线,能够直观了解到应用之间的依赖关系。基于拓扑来克隆新环境,也能批量克隆多个应用。假如多项目需求并行迭代,想要多套联调的测试环境,就可以克隆多套新环境。 Env还解决了一个资源浪费的问题,以前搭建测试环境比较随意,申请资源也很容易,其实会导致很多机器用过后,一直空置在那里。Env收拢了申请资源入口,基于Env来创建稳定分组,只能有1个,想要更多必须走审批。而对于克隆的新环境,也会有期限,14天以后会自动释放,想要延期也必须走审批。 我所负责的第一件事,就是用Env来搭建一张拓扑图,把组内所有应用都从JDOS迁移到Env上,维持稳定环境对外提供支撑对接,克隆环境对内支持多项目并行。 搭建测试环境只是起步,测试环境治理的目标是需求能够使用测试环境。对于外部依赖少的业务模块来说,这相对容易。对于外部依赖很多的业务模块来说,这就很难了。那么该如何推动这件事呢? 第1个策略是共建,让研发和测试一起来搭建和维护测试环境。 第2个策略是做功能验证,梳理出链路用例,跟踪验证结果,识别卡点问题: 对于卡点问题的处理,把干系人单独拉群对,响应超过3天就往上抛,一定会遇到推不动的问题,那么办法只能找自己的上游负责人,层层向上反馈,让上面的负责人去找对方负责人,然后推动对方的下游同学来协助解决。卡点问题记录后需要做问题分类,做好统计,这既是工作量的体现,也是每周进度汇报的依据: 第3个策略就是制定kpi,强制大家使用测试环境完成绩效。 How much,测试环境做到什么程度? 测试环境的kpi能反应出测试环境应该做到什么程度,可以使用需求使用测试环境占比和测试环境bug占比。需求使用测试环境占比的计算公式是打标了测试环境的提测卡片数/总的提测卡片数,测试在点击开始测试时,选择是否使用测试环境进行打标。测试环境bug占比的计算公式是测试环境bug/(测试环境bug+预发环境bug+生产环境bug),在提交缺陷时选择环境类型进行打标。测试环境bug占比的意义更大,因为使用测试环境与否,最终的体现还是落在缺陷上面的,比较容易量化,需求使用测试环境占比不是很确定,需求多少功能在测试环境使用了,相对来说不是很好度量,但也可以作为辅助指标进行观察。 测试环境破局 测试环境关联了很多东西,比如物料、自动化、精准、流水线等,都可以围绕测试环境来做文章。测试环境既是团队重点,也是是我个人的大案例,目前已经解决了部分困难,要想做出一鸣惊人的成绩,还需要站在更高的角度去看待整个事情,这也是一个全新的挑战,需要不断刷新自己,突破。

JaCoCo增量覆盖率的基本实现原理

本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 什么是增量覆盖率 如图所示,在master分支提交了HelloController,然后从master拉了个新分支test;提交了第1次代码,增加了WorldController;提交了第2次代码,增加了DonController。增量的获取方式有两种: 版本对比:在分支上,第2次提交和第1次提交版本对比的增量代码,就是DonController;第2次提交和刚从master拉取分支时版本对比的增量代码,除了DonController还有WorldController; 分支对比:把test分支和master分支进行对比,增量代码就是DonController和WorldController; 增量,就是通过版本对比或分支对比,多出来的新增加的那部分代码。覆盖率是指程序运行以后,有多少代码被执行到了,除以总的代码数算出来的,即覆盖率=执行代码行数/总代码行数。增量覆盖率是针对增量代码来计算的,也就是增量覆盖率=执行代码行数/增量代码行数。 基本实现原理 使用JaCoCo的On-the-fly模式,以tcpserver方式启动,将远程机器的覆盖率数据通过TCP通信dump到本地jacoco.exec文件,二次开发JaCoCo源码,实现增量覆盖率分析和输出HTML报告。 JaCoCo默认覆盖率 JaCoCo是一个开源的覆盖率工具,它的On-the-fly模式,无须侵入应用启动脚本,只需在JVM中通过-javaagent参数指定jar文件启动的代理程序,代理程序在ClassLoader装载一个class前判断是否需要注入class文件,将统计代码插入class,覆盖率分析就可以在JVM执行的过程中完成。 启动脚本示例: java -javaagent:jacocoagent.jar -jar target/app.jar 默认情况下,JaCoCo会在JVM停掉以后,生成覆盖率数据,一个jacoco.exec文件。 官方手册也有相关说明: output默认为file:At VM termination execution data is written to the file specified in the destfile attribute。这种方式有2个局限,一是必须停掉应用;二是只能把覆盖率数据生成到本地文件。 output还有另外一个选项,tcpserver: java -javaagent:jacocoagent.jar=output=tcpserver,address=0.0.0.0,port=2014 -jar target/app.jar address:服务端地址; port:服务端端口; 通过这种方式启动后,会同时启动一个TCP服务端,使用lsof -i :2014命令查看端口进程: 然后就能通过TCP通信,来获取覆盖率数据,也就是所谓的”dump“。 代码片段: @Override public void dump(String dumpPath, String ip, int port) throws IOException { dumpPath = FileUtil.getAbsolutePath(dumpPath); if (!FileUtil.exist(dumpPath)) { FileUtil.mkdir(dumpPath); } FileOutputStream localFile = new FileOutputStream(dumpPath + File.separator + "jacoco.exec"); ExecutionDataWriter localWriter = new ExecutionDataWriter(localFile); SocketAddress socketAddress = new InetSocketAddress(ip, port); Socket socket = new Socket(); try { socket.connect(socketAddress, 10000); RemoteControlWriter writer = new RemoteControlWriter(socket.getOutputStream()); RemoteControlReader reader = new RemoteControlReader(socket.getInputStream()); reader.setSessionInfoVisitor(localWriter); reader.setExecutionDataVisitor(localWriter); log.info("开始dump:{} {}", ip, port); writer.visitDumpCommand(true, false); if (!reader.read()) { log.error("Socket closed unexpectedly"); throw new IOException("Socket closed unexpectedly."); } log.info("dump完成:{} {}", ip, port); } catch (Exception e) { log.info("dump失败:{}", e.getMessage()); } finally { socket.close(); localFile.close(); } } dump经过TCP通信,将远程机器的覆盖率数据取到本地后,生成jacoco.exec文件,然后可以使用jacococli.jar生成HTML报告: ...

JMeter测试计划配置项解析

测试计划(Test Plan),是JMeter目录树的初始根节点,它的编辑区如下: