原创 | 使用JUnit、AssertJ和Mockito编写单元测试和实践TDD (八)好单元测试的特质

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

在这里插入图片描述
在这里插入图片描述

上一章讲了“CORRECT边界条件”,这一章我们讲讲“好单元测试的特质”。

好的单元测试应该具备下面的品质:

  • Automatic(自动化的)
  • Thorough(彻底的)
  • Repetable(可重复的)
  • Independent(独立的)
  • Professional(专业的)

下面分别论述

1. Automatic 自动化

单元测试应该能够自动地运行,从准备数据到执行测试到检查结果这一整个过程都不需要人工干预。

首先,调用测试的过程必须是自动化的,不需要任何人工干预步骤,例如人工输入参数值或回答YES/NO。对于测试所需要的任何预设条件(例如创建一个临时文本文件并输入指定内容)等等,都应该成为单元测试自身的一个自动化组成部分。配合Maven这样的自动化构建工具,能够做到一键执行整个项目的全部单元测试并生成测试报告。

    @Test
    void testConfig() throws Exception {
        File file = File.createTempFile("app", ".conf");
        file.deleteOnExit();
        BufferedWriter out = new BufferedWriter(new FileWriter(file));
        out.write("charset=UTF-8");
        Configuration instance = Configuration.fromFileSystem(file);
        assertThat(instance.getString("charset")).isEqualTo("UTF-8");
    }

上面的例子,为了测试用于读取配置文件的内容的Configuration类的getString()方法,必须首先存在一个包含确定内容的配置文件。我们不是在电脑上预先手工创建一个配置文件并填充内容,而是将创建文件和填充内容作为单元测试本身的一部分。这样的测试执行时就不需要人工干预了。

另一方面,检查测试结果也应该是自动化的,测试必须能够自己决定它是通过了还是失败了,而不需要人工确认。例如你要测试一个加密函数是否正确,你不应该让测试打印出加密结果,然后人工核对输出字符串和我们期望的加密后的字符串是否一样,而是由测试本身来断言二者是否相等。

    @Test
    void testEncrypt() {
        String origStr = "xxxx";
        String expectedStr = "yyyy";
        Encryptor instance = new Encryptor();
        assertThat(instance.encrypt(origStr)).isEqualTo(expectedStr);
    }

2. Thorough 彻底

好的单元测试应该覆盖了被测工作单元的每一个分支执行路径,每一个可能抛出的异常,甚至每一行代码(除了哪些getXXX()和setXXX()等极端简单,不包含逻辑的方法)。如果代码中有if…else…,你不能只是测试if这个分支,而不测试else这个分支。如果使用了switch语句,同样要测试到每一个case,以及最后的default。

3. Repetable 可重复

测试必须是可重复的,意味着:

  • 无论执行多少遍,结果都是一样的

    这意味着测试不会改变会影响它下一次运行的环境。例如一个测试往一个中央数据库插入一行数据,然后断言目前有多少行数据。这样的测试就是不可重复的,因为每次执行测试,记录行数都会加一。另外别人也可能向这个数据插入数据。解决办法是使用本地数据库(不共享),并且在每次测试之前清空数据。

  • 在任何人的电脑上执行,结果都是一样的

    这意味着测试不依赖于现有的计算机环境(操作系统,某个文件存在与否,等等)。不能只是*“在我的笔记本上能够运通过测试”*。

  • 在任何时间执行,结果都是一样的

    这意味着测试结果不受时间因素影响。如果被测代码的行为依赖于当前日期/时间(例如周末不能取款),那么在工作日和在周末执行取款测试,结果就可能不一样。这种情况下通常要重构产品代码,不要在方法内部通过

    Date now = new Date();
    

    的方式获取当前时间,而是将时间作为一个参数传递给方法:

    public void withdraw(int amount, Date withdrawTime)
    

    由客户代码负责获取当前时间并传递给Account.withdraw()方法。这样对withdraw()方法的单元测试又是可重复的了。

总之,单元测试的结果不受环境影响,也不受上次测试影响。无论如何,单元测试决不能依赖于共享资源(例如共享数据库或消息中间件),因为别人会操作这个资源,从而导致你的测试结果不确定。

4. Independent 独立

独立有两个含义:

  1. 一个测试只测试一件事情。

    每个测试都有且只有一个关注点。

  2. 测试不依赖于其他测试。也就是说,多个测试之间没有顺序依赖。

    一个测试不应该依赖于此前运行的另一个测试来为它设置测试条件(例如,第一个测试创建了文本文件并写入内容,第二个测试读取文件内容)。每个测试所需要的预设条件都应该在测试本身里面设置(第二个测试先创建文件,写入内容,再执行测试)。

5. Professional 专业

要按照编写产品代码的质量标准去编写测试代码。不要认为测试代码是二等公民,不值得为了提高它的质量而花费心力。在测试代码中,针对好设计的所有普遍规则——维护封装、采用DIY原则、降低耦合,等等等等,同样适用。

第一部分**“单元测试”就讲到这里,下一章将开始展开讲讲第二部分“测试驱动开发TDD”**,敬请关注!

在这里插入图片描述
-THE END-
原创作者 | 杨宇Yangyu
编程道与术原创内容
​转载请注明“编程道与术”出处

在这里插入图片描述

原创 | 使用JPA实现DDD持久化-JPA vs MyBatis 除了JPA之外,还有一个流行的数据访问框架MyBatis,算是个半自动化的ORM框架。 1. JPAMyBatis的比较 JPA是个全自动化的对象持久化规范,它使得开发人员只需要针对领域模型编写面向对象的代码,而不必关心底层数据存储SQL查询;而MyBatis则是一个能够灵活编写SQL语句,并将SQL的入参查询结果映射成POJOs的一个持久层框架。所以,从表面上看,JPA能方便、自动化更强,而MyBatis 在SQL语句编写方面则更灵活自由。 本质上看,JPA是面向对象的,而MyBatis是面向关系的 阅读详情

相关推荐

原创 | DDD与分层

DDD的设计思想 它本身不绑定到任何一种具体的架构风格,可以应用在多种不同的架构风格中。本文探讨在经典的分层架构中如何应用DDD,以及在DDD的语境下,分层结构每一层的具体职责。 分层架构是企业应用开发中采用率非常高的一种架构风格。它将软件系统的不同职责划分到不同的逻辑层中,并严格定义这些逻辑层的调用顺序。 在《领域驱动设计——软件核心复杂性的应对之道》一书中,DDD范式的创始人Evans提出下图...

编程道与术的博客 1068

单元测试:(二) 使用 mockito 对 service 层自动化测试入门

为什么80%的码农都做不了架构师?>>> ...

weixin_34356555的博客 1131

原创 | 使用JPA实现DDD持久化-JPA,Hibernate与Spring Data JPA

2002年,Martin Fowler在他的名著《企业应用架构模式》中首次提出“数据映射器(Data Mapper)”模式,将面向对象的领域模型映射到关系数据库中。 2003年,澳大利亚程序员Gavin King,数据系统素人,因为嫌弃EJB Entity Bean 1.1的架构复杂,自行开发了一个对象关系映射框架Hibernate。值得一提的是,此前他从未用SQL开发过任何系统。为了开发Hibernate,他临时去书店买了一个SQL基础的书。现在Hibernate已经成为最流行的对象关系影射(ORM)工具

编程道与术的博客 692

JUnit+Mockito单元测试

一、前言 1、单元测试 单元测试是指对软件中的最小可测试单元进行检查验证。 2、JUnitMockito JUnit单元测试框架。 MockitoJUnit 不同,并不是单元测试框架(这方面 JUnit 已经足够好了),它是用于生成模拟对象或者直接点说,就是”假对象“的工具。 二、环境搭建 1.9.0 1.4.12 4.11 1.6.1

Zicheng's tech blog 6384

junit与testng 分别mockito 结合使用例子

pom文件 引入: org.testng testng 6.8.8 test 使用junit: @RunWith(MockitoJUnitRunner.class) public class MockTest { @Before public void init() { MockitoAnnota

lxlmycsdnfree的博客 1802

原创 | 正确区分属性字段

很多开发人员搞不清属性字段的区别,本文试图对其作出澄清。 在进行Java软件开发的时候,很多人都没有搞清Java对象中属性(Property)字段(Field)的区别,以为属性就是字段。本文试图对这两个概念作一个澄清。 范例 首先上一个例子:平面直角坐标系中的矩形。 一个矩形的形状可以用宽(width)高(height)来表示,而它的位置可以用左下角坐标lowerLeftCoordinate(例如(10, 5))来表示。平面直角坐标系中任何一个点(Point)可以用这个点的坐标(x, y)来表示..

编程道与术的博客 1175

原创 | 使用JPA全面实现DDD持久化【关于本书】

对于任何规模的企业应用来说,数据持久化都是其中必不可少的一个关键组成部分。

编程道与术的博客 598

原创 | 使用 JUnitAssertJ Mockito 编写单元测试实践 TDD (四)关于单元测试的常见错误观念做法

上一章讲到“单元测试在整个测试体系中的位置”,这一章我们讲讲“关于单元测试的常见错误观念做法”。 很多人对单元测试存在错误的观念错误的做法。典型的错误观念做法如下: 1. 错误观念 测试是测试人员的工作。程序员只应该写产品代码 测试人员只在乎整个系统在功能外部质量方面是否满足客户用户的需求,他们既不了解、也不在乎你写的代码你的程序结构,因此他们只能编写黑盒测试而无法编写白盒测试。写代码定义内部结构是程序员的工作,通过单元测试证明你的代码结构的正确性可靠性同样是程序员的工作。 编..

编程道与术的博客 569

原创 | 使用 JPA 实现 DDD 持久化 -O 与 R: 两个世界

任何企业软件的核心都是业务逻辑的组织实现。

编程道与术的博客 555

原创 | 使用JUnitAssertJMockito编写单元测试实践TDD (一)什么是单元测试

If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization.(如果建筑业者用程序员写程序的方式盖楼造桥,那么第一只飞来驻足的啄木鸟就足以毁灭人类文明) ...

编程道与术的博客 475

原创 | 使用JUnitAssertJMockito编写单元测试实践TDD (十一)JUnit概述

JUnit 超级流行,是事实上的 Java 单元测试 TDD 的工具标准。

编程道与术的博客 474

原创 | 使用JUnitAssertJMockito编写单元测试实践TDD (九)测试驱动开发(TDD

测试驱动开发 = 测试先行 + 重构,你了解吗?

编程道与术的博客 473

原创 | 使用JUnitAssertJMockito编写单元测试实践TDD (十三)编写测试-生命周期方法

想知道编写测试中“断言、假设、使测试失效”的方法吗?

编程道与术的博客 470

原创 | 使用 JUnitAssertJ Mockito 编写单元测试实践 TDD (七)CORRECT 边界条件

我们用首字母缩略词 CORRECT 来帮助你列举需要测试的边界条件(字段或参数的取值)

编程道与术的博客 469

原创 | TDD工具集:JUnitAssertJMockito (二十三)编写测试-并行测试

分享下JUnit中是如何通过配置同步实现并行测试的!

编程道与术的博客 459

TDD集:JUnitAssertJMockito (十九)编写测试-依赖注入\测试接口\重复测试

编写测试中“依赖注入、测试接口、重复测试”的方法你 get√到了吗?

编程道与术的博客 453

原创 | 使用JUnitAssertJMockito编写单元测试实践TDD (十)在项目中准备测试环境

在准备开始测试之前,我们应该准备些什么呢?在这里可以找到答案!

编程道与术的博客 444

Kafka Streams 窗口统计怎么验收:本地跑订单流聚合,用 cpolar 给同事看只读结果页

本地用 Kafka Streams 跑订单流 5 分钟窗口聚合,把 WindowStore 结果做成只读页面,再用 cpolar 临时分享给同事验收。重点检查窗口边界、事件时间、正文图片封面是否都走 CSDN direct 图链。

qq_63013137的博客 335

【Android性能优化】Android 息屏超时自动延长机制:ScreenUndimDetector 源码级解析

本文基于 AOSP Android 16 源码,以 `ScreenUndimDetector` 为核心,深度解析 Android 的"息屏超时自动延长"机制——当用户在屏幕变暗后又手动调亮若干次时,系统会自动持有一个临时唤醒锁把屏幕多留一会儿。文中完整还原 `POLICY_DIM → POLICY_BRIGHT` 的状态跃迁检测、`mUndimCounter` 连续变亮计数与 `mMaxDurationBetweenUndimsMillis` 间隔重置逻辑。

weixin_44081096的博客 136
上一篇: 原创 | 使用 JUnit、AssertJ 和 Mockito 编写单元测试和实践 TDD (七)CORRECT 边界条件
下一篇: 原创 | 使用JUnit、AssertJ和Mockito编写单元测试和实践TDD (九)测试驱动开发(TDD)
编程道与术
博客等级 码龄6年 13粉丝 42原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值