超详细的单元测试总结

一、何为单测

测试有黑盒测试和白盒测试之分,黑盒测试顾名思义就是我们不了解盒子的内部结构,我们通过文档或者对该功能的理解,指定了相应的输入参数,然后判断得出的结果是否正确。普通的用户、开发、QA都可以进行黑盒测试。

白盒测试与之相反,需要了解到内部的实现细节,一般是由开发人员自己来进行的,是基于对代码逻辑结构、各个关联方法了解基础上进行的。

白盒测试主要有 2 种

  • 静态代码分析:Findbugs、Sonarqube
  • 动态测试:单元测试

单元测试属于白盒测试里面的动态测试

二、单测的意义

2.1 解决问题的成本

测试金字塔,是单测中一张经典的图片。测试级别简单可以简单分为下面三类,详细的话可以归结为:单元测试、接口测试、集成测试、系统测试、验收测试。

如果发现问题,在金字塔越底层的阶段,解决问题的速度是越快的。


2.2 维护系统的稳定性

我代码已经写好了挺久了,线上也运行一段时间了,还有必要补充单测吗?感觉单测写了一堆并没有发现问题,不知道价值点在哪。

  1. 校验你当前方法的正确性。
  2. 长时间保证你这个方法的稳定性,在往后需求的变更开发中,可能其他功能点影响到了这个方法,此时你的单测能很快帮你检查出来。
  3. 单测能够在你项目需要重构的时候,勇敢大步的往前走。与其反反复复修改问题,系统摇摇欲坠的,不如多花点时间优化代码,写写单测。

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~3:1,所以如果公司决定了写单测就同时也要给与这部分的时间。不能即催着业务上线,又催着单测达标,特别是前期在对单测还不够熟悉的基础上。

9.单测维护成本

单测也是需要维护的,case 多了后会发现,一有业务调整,不单单业务代码要调,单测也要调整,否则 case 会失败。

四、单测框架说明

1.Jmock

2.Mockito

3.JMockit

4.EasyMock

5.testNg

6.Spock

7.TestableMock

8.junit4

9.junit5

10.Springtest

https://www.cnblogs.com/itplay/p/10101260.html

兼容多种测试引擎,便捷傻瓜,但是有下面几个问题

11.总结
框架非常多,选择框架的时候可以从下面几个点考虑:
12.语法好写吗,文档全吗
13.能 mock 静态类,静态方法吗

Fastjunit = junit5 + jmockit + 测试工具集

单测框架总类繁多,本人很多都没有了解到位,以上总结仅为一家之言,兼听则明。

五、最佳实践

5.1. 理论知识要记牢

  1. - 用例要轻量,执行速度要够快

  2. - 执行过后没有痕迹

  3. - 不依赖特点环境,随处都可以执行

  4. - 校验要全面

AI写代码python运行

5.2. 测试代码模板

单测的代码跟业务代码一样,需要易于阅读,方便维护。

  1. 再复杂的用例都要清晰得看出下面 3 个步骤

  2. 1. 上下文设置:参数模拟,mock 无用服务

  3. 2. 触发测试用例执行

  4. 3. 结果断言

  1. /**

  2. * Given 给定上下文【初始化数据,Mock 外部调用】

  3. */

  4. new Expectations(EsClient.class) {

  5. {

  6. EsClient.createDoc(withInstanceOf(SimpleDocVo.class), withInstanceOf(PipelineJobJunit.class));

  7. result = "{}";

  8. times = 1;

  9. }

  10. };

  11. /**

  12. * 执行测试代码

  13. */

  14. RestResponse restResponse = callBackController.junitCallBak(jenkinsJunitVo);

  15. /**

  16. * Assert 要足够细致

  17. */

  18. Assertions.assertThat(restResponse).hasFieldOrPropertyWithValue("code", 0);

5.3 TDD 测试驱动开发

好的代码编写测试用例的时候是比较顺畅的,如果写单测的时候觉得目标代码很难测试,这时候大概率是目标代码编写不合理,需要优化重构下。另一方面,如果在写业务代码的时候先写好单测框架,此时能反向推动你写成比较好的代码。

5.3.1 松散代码

业务逻辑平铺在一个方法里面,此时你的单测不好关注主流程,也很难 mock 其它无用的东西(因为比较多)。此时为了让我们的单测好写,可以反向推动业务代码朝着高内聚低耦合的方向重构。

下面红框中的逻辑可以抽出来,主流程就清晰很多,用例也好写很多。

5.3.2 不稳定的代码

此方法里读取当前系统时间并根据该值返回结果。Datetime.now 是一个隐藏的动态变量,整个方法的输出结果依赖于 datetime 的时间。

  1. public static string GetTimeOfDay()

  2. {

  3. DateTime time = DateTime.Now;

  4. if (time.Hour >= 0 && time.Hour < 6>= 6 && time.Hour < 12>= 12 && time.Hour < 18 xss=removed>= 0 && dateTime.Hour < 6>= 6 && dateTime.Hour < 12>= 12 && dateTime.Hour < 18 xss=removed xss=removed xss=removed> StringUtil.isNotEmpty(simpleDocVo.getId()));

  5. Assertions.assertThat(document)

  6. .hasFieldOrPropertyWithValue("pipelineJobId", jenkinsJunitVo.getUapJobId())

  7. .hasFieldOrPropertyWithValue("status", jenkinsJunitVo.getStatus())

  8. .hasFieldOrPropertyWithValue("allCoverage", jenkinsJunitVo.getAllCoverage())

  9. .hasFieldOrPropertyWithValue("newCoverage", jenkinsJunitVo.getNewCoverage())

  10. .hasFieldOrPropertyWithValue("testRun", jenkinsJunitVo.getTestRun())

  11. .hasFieldOrPropertyWithValue("testFailure", jenkinsJunitVo.getTestFailure())

  12. .hasFieldOrPropertyWithValue("testSkipped", jenkinsJunitVo.getTestSkipped());

  13. }

  14. };

5.4造数据

你还在一个个属性的添加吗?

  1. @Test

  2. public void webhookTestWebhook() {

  3. OtptestWebhookQueryDTO dto = new OtptestWebhookQueryDTO();

  4. dto.setApp("uap");

  5. dto.setEnv("test");

  6. dto.setJobId("xxx");

  7. dto.setVersion("v2.2");

  8. xxx

  9. }

http://fastjunit.kubeclub.cn/test-basic/dataProvider/

Fastjunit 的数据生成器,任意给个 Bean 对象,自动的根据字段属性帮你随机产生相关数据。也支持数组对象的随机生成。可以节约不少时间。

5.5参数化测试

多种分支场景,使用参数化的测试可以让你的用例更简单。

  1. @ParameterizedTest(name = "{0} + {1} = {2}")

  2. @CsvSource({

  3. "0, 1, 1",

  4. "1, 2, 3",

  5. "49, 51, 100",

  6. "1, 100, 101"

  7. })

  8. void add(int first, int second, int expectedResult) {

  9. Calculator calculator = new Calculator();

  10. assertEquals(expectedResult, calculator.add(first, second),

  11. () -> first + " + " + second + " should equal " + expectedResult);

  12. }

5.6 数据库测试 - H2

H2 是一个内存数据,H2 仅仅只支持简单标准的 SQL 语法,如果各厂商特有的数据库引擎的特殊函数,可以使用 H2Function 扩展。

Fastjunit 同样对 H2 进行了一些封装:http://fastjunit.kubeclub.cn/db/h2/

5.7 并行测试

CICD 融入单测的过程,可能导致构建速度变慢,此时如果你的测试是并行的话,能在一定程度提高执行的速度。

5.8 IDEA 快捷键

多了解些快捷键,在单测的过程中执行一些批量操作还是挺有效率的。如 bean 十几个、几十个属性,要批量赋值,批量校验的一些场景。

5.9 单测的范围

5.10 单测报告 - Jacoco

http://fastjunit.kubeclub.cn/test-basic/jacoco-report/

六、Jmockit 简单说明

6.1 示例

  1. class ExampleTest {

  2. @Tested ServiceAbc tested;

  3. @Injectable DependencyXyz mockXyz;

  4. @Test

  5. void doOperationAbc(@Mocked AnotherDependency anyInstance) {

  6. new Expectations() {{

  7. anyInstance.doSomething(anyString); result = 123;

  8. AnotherDependency.someStaticMethod(); result = new IOException();

  9. }};

  10. tested.doOperationAbc("some data");

  11. new Verifications() {{ mockXyz.complexOperation(true, anyInt, null); times = 1; }};

  12. }

  13. }

  1. 实例化和属性注入:@Tested 自动实例化 ServiceAbc 对象,并把 @Injectable DependencyXyz 属性自动注入到 tested 里面。
  2. 模拟期望:Expectations 内部的匿名方法会实现对象的模拟和期望。
  1. // anyInstance 对象的 doSomething 方法被调用的时候将返回 123

  2. // 收到的参数需要是任意的字符类型 anyString ,万一收到一个 int,就不会返回 123 了

  3. anyInstance.doSomething(anyString); result = 123;

AI写代码python运行

6.2 @Capturing

@Mocked 一般是 mock 具体的对象,像一些接口或者基类,我们只知道具体的实现类,这种场景可以用 @Capturing。(例如:像一些权限校验,AOP 代理自动生成的场景)

  1. //权限类,校验用户没有权限访问某资源

  2. public interface IPrivilege {

  3. /**

  4. * 判断用户有没有权限

  5. * @param userId

  6. * @return 有权限,就返回true,否则返回false

  7. */

  8. public boolean isAllow(long userId);

  9. }

  1. @Test

  2. public void testCaputring(@Capturing IPrivilege privilegeManager) {

  3. // 加上了JMockit的API @Capturing,

  4. // JMockit会帮我们实例化这个对象,它除了具有@Mocked的特点,还能影响它的子类/实现类

  5. new Expectations() {

  6. {

  7. // 对IPrivilege的所有实现类录制,假设测试用户有权限

  8. privilegeManager.isAllow(testUserId);

  9. result = true;

  10. }

  11. };

  12. // 不管权限校验的实现类是哪个,这个测试用户都有权限

  13. Assert.assertTrue(privilegeManager1.isAllow(testUserId));

  14. Assert.assertTrue(privilegeManager2.isAllow(testUserId));

  15. }

6.3 参数的灵活匹配

在录制和验证阶段,一个对模拟方法或构造方法的调用参数做灵活的匹配。

1.any

最不严格的参数匹配,当然每个方法的参数都有类型的,还是要给定个恰当的参数类型。

  1. new Expectations() {{

  2. abc.voidMethod(anyString, (List&lt;?&gt;) any);

  3. }};

AI写代码python运行

2.with

  1. // 不为空即可

  2. abc.voidMethod("str", (List&lt;?&gt;) withNotNull());

  3. // 需要是什么类型,需要包含 xyz 字符

  4. abc.stringReturningMethod(withSameInstance(item), withSubstring("xyz"));

  5. // 前缀需要是 abc

  6. mock.doSomething(anyInt, true, withPrefix("abc"));

  7. // 更多查看接口文档

AI写代码python运行

6.4 调用次数约束/验证

  1. // 该方法最少被调用 2 次

  2. abc.voidMethod(); minTimes = 2;

  3. // 被调用 1~5 次

  4. abc.stringReturningMethod(); minTimes = 1; maxTimes = 5;

  5. // 最多被调用 1 次

  6. abc.anotherVoidMethod(3); maxTimes = 1;

6.5 从调用方法中捕捉参数,并对参数进一步验证

  1. new Verifications() {{

  2. double d;

  3. String s;

  4. mock.doSomething(d = withCapture(), null, s = withCapture());

  5. assertTrue(d > 0.0);

  6. assertTrue(s.length() > 1);

  7. }};

七、结尾

单测相关的意义开头已经讲了,这边不重复总结,补充下下面 2 点。

1.麻烦事

2.收获

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1200899.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何判断一个B2B平台开发服务商是否专业?商联达告诉你

判断 B2B 平台开发服务商是否专业&#xff0c;核心看技术硬实力、行业深耕度、项目交付与服务体系、安全合规能力及可持续发展潜力&#xff0c;商联达结合 12 年产业互联网实战经验&#xff0c;为你拆解可落地的评估标准与验证方法。一、技术硬实力&#xff1a;稳定、先进、可扩…

在吴忠码上俱乐部,遇见你的羽球引路人

在吴忠&#xff0c;有一处备受羽毛球爱好者青睐的活力空间——吴忠码上羽毛球俱乐部。这里&#xff0c;不仅是挥洒汗水的球场&#xff0c;更是一个在专业指导下&#xff0c;系统感受羽毛球魅力、共同成长的社区。俱乐部的核心教练韩宁波&#xff0c;以其国家二级运动员的专业背…

什么是DDOS攻击?以及如何防御DDOS攻击

什么是DDOS攻击&#xff1f; 所谓的 DDoS 攻击&#xff0c;全称是 Distributed Denial of Service&#xff0c;翻译成中文就是分布式拒绝服务。一般来说是指攻击者利用“肉鸡”对目标网站在较短的时间内发起大量请求&#xff0c;大规模消耗目标网站的主机资源&#xff0c;让它…

PHP 基础案例教程之 02-PHP 语法基础

基本语法 PHP 标记 PHP 代码可以嵌入 HTML 中使用&#xff0c;为了区分 PHP 代码和 HTML 代码&#xff0c;需要使用 PHP 标记对 PHP 代码进行标识&#xff0c;PHP 的标记分为标准标记和短标记。 PHP 标记的基本用法&#xff1a; <?php 代码块 ?> <? 代码块 ?&…

2025年数据恢复软件免费版最真实推荐—— 18年老工程师深度评测

大家好&#xff0c;我是做了18年数据恢复的工程师&#xff0c;每天都在和各种丢失数据打交道。免费软件到底能不能救数据&#xff1f;我的结论是&#xff1a;能&#xff0c;但极其有限。绝大多数情况下&#xff0c;免费版只能救“轻度丢失”&#xff0c;真正严重的情况&#xf…

力扣337 打家劫舍 III java实现

337.打家劫舍 III 小偷又发现了一个新的可行窃的地区。这个地区只有一个入口&#xff0c;我们称之为 root 。 除了 root 之外&#xff0c;每栋房子有且只有一个“父“房子与之相连。一番侦察之后&#xff0c;聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。…

不同类型的代理服务器解析

代理的差异各不相同 - 尤其是住宅代理和数据中心代理之间。这意味着重新路由和 IP 隐藏的方法因代理类型而异。住宅代理会为每个来自物理设备的连接分配一个新 IP。而数据中心代理服务则从数据中心获取 IP。也就是说&#xff0c;它们不会为每个请求分配新 IP。以下是不同类型的…

Vue.js 前端开发实战之 04-Vue 开发基础(3)

全局 API Vue.directive Vue 中有很多内置指令&#xff0c;除了内置指令外还可以根据需求使用 Vue.directive 注册自定义指令。 Vue.directive 的基本用法&#xff1a; <div id"app"><input type"text" v-指令名称"指令的值"> &…

红队工具箱:进攻性安全运营的必备工具与技术

免责声明&#xff1a; 本文仅用于教育目的。未经授权利用系统是非法行为&#xff0c;将受到法律制裁。保持道德。遵守法律。安全负责。 感谢各位阅读。享受愉快的道德黑客之旅&#xff01;如果喜欢我的工作&#xff0c;请支持我&#xff01; &#x1f525; 红队介绍 红队演…

AMAT 0270-20268

该部件是Applied Materials&#xff08;应用材料公司&#xff09;的备件编号&#xff0c;用于半导体制造设备中的PCII&#xff08;可能是某种工艺腔室&#xff09;钟罩&#xff08;Bell Jar&#xff09;的喷砂&#xff08;Bead Blast&#xff09;夹具。以下是相关信息和可能的用…

如何判断B2B平台开发服务商的技术硬实力?

在产业数字化转型加速推进的当下&#xff0c;B2B电商平台已从简单的信息撮合工具&#xff0c;升级为整合供应链全链路资源的核心基础设施。对于企业而言&#xff0c;选择一家技术硬实力过硬的B2B平台开发服务商&#xff0c;直接决定了平台的稳定性、扩展性与长期运营价值。然而…

学霸同款2026 TOP10 AI论文写作软件:自考毕业论文全攻略

学霸同款2026 TOP10 AI论文写作软件&#xff1a;自考毕业论文全攻略 2026年自考论文写作工具测评&#xff1a;为何需要一份精准榜单&#xff1f; 随着AI技术的不断进步&#xff0c;越来越多的自考学生开始借助AI写作工具提升毕业论文的完成效率。然而&#xff0c;市面上的工具…

【AI避坑指南】pdfQA基准:表格成“拦路虎“,GPT-120B也栽跟头,大模型开发必看!

论文信息&#xff1a;pdfQA: Diverse, Challenging, and Realistic Question Answering over PDFs, Published on arXiv on 5 Jan 2026, by University of Zurich & ETH Zurich ⚡ TL;DR: 现有的 RAG 评测太“干净”了&#xff01;这篇论文推出了 pdfQA——一个包含 4K 高难…

XSS 攻击(详细) 攻击类型、攻击技巧、攻击工具与平台、防御方法

目录 引言 一、XSS 攻击简介 二、XSS 攻击类型 1.反射型 XSS 2.存储型 XSS 3.基于 DOM 的 XSS 4.Self - XSS 三、XSS 攻击技巧 1.基本变形 2.事件处理程序 3.JS 伪协议 4.编码绕过 5.绕过长度限制 6.使用标签 四、XSS 攻击工具与平台 1.XSS 攻击平台 2.BEEF …

那些让你头疼的外部群推送难题,真相其实是这样的

QiWe开放平台 个人名片 API驱动企微自动化&#xff0c;让开发更高效 核心能力&#xff1a;为开发者提供标准化接口、快速集成工具&#xff0c;助力产品高效拓展功能场景 官方站点&#xff1a;https://www.qiweapi.com 团队定位&#xff1a;专注企微API生态的技术服务团队 对接…

学术论文辅助工具盘点:8款顶尖AI翻译与润色软件评测

&#xfffd;&#xfffd; 8款英文论文AI写作工具核心对比 工具名称 核心功能 处理速度 适合场景 独特优势 aibiye 降AIGC率查重 20分钟 学术论文优化 适配知网/维普检测规则 aicheck AIGC检测降重 20分钟 AI生成内容处理 双重检测降重一体化 askpaper 学术风格…

超重力床在环保领域的具体应用

超重力床(又称旋转填充床)是基于超重力场强化传质原理的新型设备,通过高速旋转产生数十至数百倍重力加速度,使气液两相在填料内形成巨大相界面,大幅提升传质效率,相比传统塔器体积缩小90%以上。其在环保领域的应…

企微API外部群自动化:快速建立自己的护城河

QiWe开放平台 个人名片 API驱动企微自动化&#xff0c;让开发更高效 核心能力&#xff1a;为开发者提供标准化接口、快速集成工具&#xff0c;助力产品高效拓展功能场景 官方站点&#xff1a;https://www.qiweapi.com 团队定位&#xff1a;专注企微API生态的技术服务团队 对接…

智能论文写作辅助:八大翻译优化与语言增强工具评测

&#xfffd;&#xfffd; 8款英文论文AI写作工具核心对比 工具名称 核心功能 处理速度 适合场景 独特优势 aibiye 降AIGC率查重 20分钟 学术论文优化 适配知网/维普检测规则 aicheck AIGC检测降重 20分钟 AI生成内容处理 双重检测降重一体化 askpaper 学术风格…

网络安全 | 深入解析XSS攻击与防御实战

网络安全 | 深入解析XSS攻击与防御实战 XSS攻击概述 跨站脚本攻击(Cross-Site Scripting&#xff0c;简称XSS)是一种常见的Web安全漏洞&#xff0c;它允许攻击者将恶意客户端脚本注入到其他用户浏览的网页中。XSS攻击的危害等级通常被OWASP评为高风险漏洞&#xff0c;攻击者可…