一加网站开发,wordpress企业建站教程 百度 下载,响应式布局网站模板,唐山cms模板建站#x1f345; 点击文末小卡片#xff0c;免费获取软件测试全套资料#xff0c;资料在手#xff0c;涨薪更快 一、何为单测
测试有黑盒测试和白盒测试之分#xff0c;黑盒测试顾名思义就是我们不了解盒子的内部结构#xff0c;我们通过文档或者对该功能的理解#xff0c… 点击文末小卡片免费获取软件测试全套资料资料在手涨薪更快 一、何为单测
测试有黑盒测试和白盒测试之分黑盒测试顾名思义就是我们不了解盒子的内部结构我们通过文档或者对该功能的理解指定了相应的输入参数然后判断得出的结果是否正确。普通的用户、开发、QA都可以进行黑盒测试。
白盒测试与之相反需要了解到内部的实现细节一般是由开发人员自己来进行的是基于对代码逻辑结构、各个关联方法了解基础上进行的。 白盒测试主要有 2 种
静态代码分析Findbugs、Sonarqube动态测试单元测试
单元测试属于白盒测试里面的动态测试
二、单测的意义
2.1 解决问题的成本
测试金字塔是单测中一张经典的图片。测试级别简单可以简单分为下面三类详细的话可以归结为单元测试、接口测试、集成测试、系统测试、验收测试。 如果发现问题在金字塔越底层的阶段解决问题的速度是越快的。
本地开发环境发现问题看几眼代码或者 debug 下就能定位出来了。生产环境发现问题找日志可能还没有输出查数据库可能没权限。本地能复现的话还好复现不了的话干着急。 2.2 维护系统的稳定性
我代码已经写好了挺久了线上也运行一段时间了还有必要补充单测吗感觉单测写了一堆并没有发现问题不知道价值点在哪。
校验你当前方法的正确性。长时间保证你这个方法的稳定性在往后需求的变更开发中可能其他功能点影响到了这个方法此时你的单测能很快帮你检查出来。单测能够在你项目需要重构的时候勇敢大步的往前走。与其反反复复修改问题系统摇摇欲坠的不如多花点时间优化代码写写单测。
2.3 单测与持续集成的融合 单测 CICD 自动化测试
每次打包的时候自动跑单测用例有问题快速反馈。没问题的代码才可以触发部署到对应的环境中。避免测试不足的代码提交到相关环境导致服务用不了测试人员一顿恼火。
三、单测拦路虎
1.框架繁多
新手对单测的框架没有意识自己可能引用了一种 其它框架 sdk 里面包含了另一种比如 spring 的 framework 可能本身版本也五花八门junit4 junit5 都有使用的时候没注意乱用。 用了 junit5 写的用例然后用 junit4 的 Ignore 语法要去忽略这个单测显然不行因为在 junit5 对应的语法是 Disabled
Injectable MockMethod Mock Test … 迷茫
2.缺少理论的实践
3.对单测的理念认同不够赶鸭子上架内心其实是抵触的。
4.用例泛泛而写没有遵守用例核心三步骤mock 数据 - 方法触发 - 结果校验
5.为了覆盖率而写的单测
6.为了证明你方法是对的而写的单测单测后面补的单测里面方法触发了就算写完了不是抱着验证的态度对所有结果进行充分细致的校验
7.代码逻辑太复杂单测太难写
可以在写单测的过程推动部分方法的重构。如果是新代码可以用 TDD测试驱动开发 理念先写单测再写业务代码这样实现起来的业务代码比较能做到高内聚低耦合。
8.业务压力太大单测太耗时
单测代码编写时间业务代码编写时间 2~31所以如果公司决定了写单测就同时也要给与这部分的时间。不能即催着业务上线又催着单测达标特别是前期在对单测还不够熟悉的基础上。
9.单测维护成本
单测也是需要维护的case 多了后会发现一有业务调整不单单业务代码要调单测也要调整否则 case 会失败。
四、单测框架说明
1.Jmock
网站jMock - An Expressive Mock Object Library for Java不能对静态方法Mock
2.Mockito
官方主页 http://code.google.com/p/mockito/不能对静态方法Mock
3.JMockit
http://jmockit.github.io/功能强大可以 mock 静态方法
4.EasyMock
官方主页 http://www.easymock.org/
5.testNg
TestNG可以进行单元测试功能测试端到端测试集成测试等。需要一个额外的xml配置文件配置测试的class、method甚至package
6.Spock
https://tech.meituan.com/tags/spock.htmlBDD 的单测写法Groovy 语法快速但是跟我们 java 的编码习惯不大一样。无法 mock 静态方法。
7.TestableMock
文档https://alibaba.github.io/testable-mock/#/zh-cn/doc/setupTestableMock 和 JMockit 底层一致使用的是 “运行时字节码修改” 技术在单元测试启动时就扫描测试类和被测类的字节码完成 Mock 方法的替换。
8.junit4
Java领域内最为流行的单元测试框架
9.junit5
JUnit 5 JUnit Platform JUnit Jupiter JUnit VintageJUnit Platform: Junit Platform是在JVM上启动测试框架的基础不仅支持Junit自制的测试引擎其他测试引擎也都可以接入。JUnit Jupiter: JUnit Jupiter提供了JUnit5的新的编程模型是JUnit5新特性的核心。内部 包含了一个测试引擎用于在Junit Platform上运行。JUnit Vintage: 由于JUint已经发展多年为了照顾老的项目JUnit Vintage提供了兼容JUnit4.x,Junit3.x的测试引擎。
10.Springtest
https://www.cnblogs.com/itplay/p/10101260.html
兼容多种测试引擎便捷傻瓜但是有下面几个问题
可能存在多次启动 spring 容器一次 case 可能加载很多不需要的 bean 导致速度很慢
11.总结 框架非常多选择框架的时候可以从下面几个点考虑 12.语法好写吗文档全吗 13.能 mock 静态类静态方法吗
推荐 junit5 ( jmockit | testableMock)有冒险精神的可以尝试 Spock速度快但是静态方法的 mock 需要借助其它工具。
Fastjunit junit5 jmockit 测试工具集
单测框架总类繁多本人很多都没有了解到位以上总结仅为一家之言兼听则明。
五、最佳实践
5.1. 理论知识要记牢
- 用例要轻量执行速度要够快
- 执行过后没有痕迹
- 不依赖特点环境随处都可以执行
- 校验要全面5.2. 测试代码模板
单测的代码跟业务代码一样需要易于阅读方便维护。
再复杂的用例都要清晰得看出下面 3 个步骤
1. 上下文设置参数模拟mock 无用服务
2. 触发测试用例执行
3. 结果断言/*** Given 给定上下文【初始化数据Mock 外部调用】*/
new Expectations(EsClient.class) {{EsClient.createDoc(withInstanceOf(SimpleDocVo.class), withInstanceOf(PipelineJobJunit.class));result {};times 1;}
};
/*** 执行测试代码*/
RestResponse restResponse callBackController.junitCallBak(jenkinsJunitVo);/*** Assert 要足够细致*/
Assertions.assertThat(restResponse).hasFieldOrPropertyWithValue(code, 0);5.3 TDD 测试驱动开发
好的代码编写测试用例的时候是比较顺畅的如果写单测的时候觉得目标代码很难测试这时候大概率是目标代码编写不合理需要优化重构下。另一方面如果在写业务代码的时候先写好单测框架此时能反向推动你写成比较好的代码。
5.3.1 松散代码
业务逻辑平铺在一个方法里面此时你的单测不好关注主流程也很难 mock 其它无用的东西因为比较多。此时为了让我们的单测好写可以反向推动业务代码朝着高内聚低耦合的方向重构。 下面红框中的逻辑可以抽出来主流程就清晰很多用例也好写很多。 5.3.2 不稳定的代码
此方法里读取当前系统时间并根据该值返回结果。Datetime.now 是一个隐藏的动态变量整个方法的输出结果依赖于 datetime 的时间。
public static string GetTimeOfDay()
{DateTime time DateTime.Now;if (time.Hour 0 time.Hour 6 6 time.Hour 12 12 time.Hour 18 xssremoved 0 dateTime.Hour 6 6 dateTime.Hour 12 12 dateTime.Hour 18 xssremoved xssremoved xssremoved StringUtil.isNotEmpty(simpleDocVo.getId()));Assertions.assertThat(document).hasFieldOrPropertyWithValue(pipelineJobId, jenkinsJunitVo.getUapJobId()).hasFieldOrPropertyWithValue(status, jenkinsJunitVo.getStatus()).hasFieldOrPropertyWithValue(allCoverage, jenkinsJunitVo.getAllCoverage()).hasFieldOrPropertyWithValue(newCoverage, jenkinsJunitVo.getNewCoverage()).hasFieldOrPropertyWithValue(testRun, jenkinsJunitVo.getTestRun()).hasFieldOrPropertyWithValue(testFailure, jenkinsJunitVo.getTestFailure()).hasFieldOrPropertyWithValue(testSkipped, jenkinsJunitVo.getTestSkipped());}
};5.4造数据
你还在一个个属性的添加吗
Test
public void webhookTestWebhook() {OtptestWebhookQueryDTO dto new OtptestWebhookQueryDTO();dto.setApp(uap);dto.setEnv(test);dto.setJobId(xxx);dto.setVersion(v2.2);xxx
}http://fastjunit.kubeclub.cn/test-basic/dataProvider/ Fastjunit 的数据生成器任意给个 Bean 对象自动的根据字段属性帮你随机产生相关数据。也支持数组对象的随机生成。可以节约不少时间。
5.5参数化测试
多种分支场景使用参数化的测试可以让你的用例更简单。
ParameterizedTest(name {0} {1} {2})
CsvSource({0, 1, 1,1, 2, 3,49, 51, 100,1, 100, 101
})
void add(int first, int second, int expectedResult) {Calculator calculator new Calculator();assertEquals(expectedResult, calculator.add(first, second),() - first second should equal expectedResult);
}5.6 数据库测试 - H2
H2 是一个内存数据H2 仅仅只支持简单标准的 SQL 语法如果各厂商特有的数据库引擎的特殊函数可以使用 H2Function 扩展。
Fastjunit 同样对 H2 进行了一些封装http://fastjunit.kubeclub.cn/db/h2/
5.7 并行测试
CICD 融入单测的过程可能导致构建速度变慢此时如果你的测试是并行的话能在一定程度提高执行的速度。
Junit5-parallelSurefire-parallel http://maven.apache.org/surefire/maven-surefire-plugin/examples/fork-options-and-parallel-execution.html
5.8 IDEA 快捷键
多了解些快捷键在单测的过程中执行一些批量操作还是挺有效率的。如 bean 十几个、几十个属性要批量赋值批量校验的一些场景。
5.9 单测的范围 5.10 单测报告 - Jacoco
http://fastjunit.kubeclub.cn/test-basic/jacoco-report/
六、Jmockit 简单说明
6.1 示例
class ExampleTest {Tested ServiceAbc tested;Injectable DependencyXyz mockXyz;Testvoid doOperationAbc(Mocked AnotherDependency anyInstance) {new Expectations() {{anyInstance.doSomething(anyString); result 123;AnotherDependency.someStaticMethod(); result new IOException();}};tested.doOperationAbc(some data);new Verifications() {{ mockXyz.complexOperation(true, anyInt, null); times 1; }};}
}实例化和属性注入Tested 自动实例化 ServiceAbc 对象并把 Injectable DependencyXyz 属性自动注入到 tested 里面。模拟期望Expectations 内部的匿名方法会实现对象的模拟和期望。 // anyInstance 对象的 doSomething 方法被调用的时候将返回 123// 收到的参数需要是任意的字符类型 anyString 万一收到一个 int就不会返回 123 了anyInstance.doSomething(anyString); result 123;6.2 Capturing
Mocked 一般是 mock 具体的对象像一些接口或者基类我们只知道具体的实现类这种场景可以用 Capturing。例如像一些权限校验AOP 代理自动生成的场景 //权限类校验用户没有权限访问某资源public interface IPrivilege {/*** 判断用户有没有权限* param userId* return 有权限就返回true,否则返回false*/public boolean isAllow(long userId);
}Test
public void testCaputring(Capturing IPrivilege privilegeManager) {
// 加上了JMockit的API Capturing,
// JMockit会帮我们实例化这个对象它除了具有Mocked的特点还能影响它的子类/实现类
new Expectations() {{// 对IPrivilege的所有实现类录制假设测试用户有权限privilegeManager.isAllow(testUserId);result true;}
};
// 不管权限校验的实现类是哪个这个测试用户都有权限
Assert.assertTrue(privilegeManager1.isAllow(testUserId));
Assert.assertTrue(privilegeManager2.isAllow(testUserId));
}6.3 参数的灵活匹配
在录制和验证阶段一个对模拟方法或构造方法的调用参数做灵活的匹配。
1.any
最不严格的参数匹配当然每个方法的参数都有类型的还是要给定个恰当的参数类型。
new Expectations() {{abc.voidMethod(anyString, (Listlt;?gt;) any);
}};2.with
// 不为空即可
abc.voidMethod(str, (Listlt;?gt;) withNotNull());// 需要是什么类型需要包含 xyz 字符
abc.stringReturningMethod(withSameInstance(item), withSubstring(xyz));// 前缀需要是 abc
mock.doSomething(anyInt, true, withPrefix(abc));// 更多查看接口文档6.4 调用次数约束/验证
// 该方法最少被调用 2 次
abc.voidMethod(); minTimes 2;// 被调用 1~5 次
abc.stringReturningMethod(); minTimes 1; maxTimes 5;// 最多被调用 1 次
abc.anotherVoidMethod(3); maxTimes 1;6.5 从调用方法中捕捉参数并对参数进一步验证
new Verifications() {{double d;String s;mock.doSomething(d withCapture(), null, s withCapture());assertTrue(d 0.0);assertTrue(s.length() 1);
}};七、结尾
单测相关的意义开头已经讲了这边不重复总结补充下下面 2 点。
1.麻烦事
业务代码的改动单测要跟着改动不要之前写了单测后面业务调整导致已有单测失败了就简单的给 ignore 了。要一开始就规划好单测不要写好业务代码后续补单测。已经稳定的代码补单测的意义不大。
2.收获
提升开发素养不做 CRUD 程序员单测的工作中会让你深入了解各个代码甚至中间件的实现逻辑深入底层了解内部实现。
最后感谢每一个认真阅读我文章的人礼尚往来总是要有的虽然不是什么很值钱的东西如果你用得到的话可以直接拿走 这些资料对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库这个仓库也陪伴我走过了最艰难的路程希望也能帮助到你凡事要趁早特别是技术行业一定要提升技术功底。