当前位置: 首页 > news >正文

【JUnit实战3_03】第二章:探索 JUnit 的核心功能(二)

JUnit in Action, Third Edition

《JUnit in Action》全新第3版封面截图

写在前面
再次强调,这一章的重点是快速扫盲,因此知识点相对密集,但并未深入展开讨论。梳理本章知识点时我也只记录核心要点,只在个别实测过程中略作补充。现在 AI 工具如此便捷,对提到的 JUnit 特性如果有疑问,可以快速得到满意的答复。对于需要夯实基础的朋友来说,能逐一消化每个功能特性固然很好;如果条件不允许,至少也要建立印象,以便今后知道往什么方向查阅资料。

文章目录

    • 2.5 @DisplayName 注解
    • 2.6 @Nested 注解
    • 2.7 @Tag 注解
    • 2.8 断言方法
    • 2.9 新版超时断言
    • 2.10 需要抛出异常的断言测试
    • 2.11 假设断言

2.5 @DisplayName 注解

(详见 上一篇)

2.6 @Nested 注解

用于测试内部类中的待测试方法。

内部类的经典应用场景是通过 Builder 模式初始化一个类(强烈建议自行手动实现一遍 Customer 实体类,加深印象):

public class Customer {private final Gender gender;private final String firstName;private final String lastName;private final String middleName;private final Date becomeCustomer;public static class Builder {private final Gender gender;private final String lastName;private final String firstName;private String middleName;private Date becomeCustomer;public Builder(Gender gender, String firstName, String lastName) {this.gender = gender;this.firstName = firstName;this.lastName = lastName;}public Builder withMiddleName(String middleName) {this.middleName = middleName;return this;}public Builder withBecomeCustomer(Date becomeCustomer) {this.becomeCustomer = becomeCustomer;return this;}public Customer build() {return new Customer(this);}}private Customer(Builder builder) {this.gender = builder.gender;this.firstName = builder.firstName;this.lastName = builder.lastName;this.middleName = builder.middleName;this.becomeCustomer = builder.becomeCustomer;}// getters
}

@Nested 注解的用法(L5):

public class NestedTestsTest {private static final String FIRST_NAME = "John";private static final String LAST_NAME = "Smith";@Nested()class BuilderTest {private final String MIDDLE_NAME = "Michael";@Testvoid customerBuilder() throws ParseException {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM-dd-yyyy");Date customerDate = simpleDateFormat.parse("04-21-2019");Customer customer = new Customer.Builder(Gender.MALE, FIRST_NAME, LAST_NAME).withMiddleName(MIDDLE_NAME).withBecomeCustomer(customerDate).build();assertAll(() -> {assertEquals(Gender.MALE, customer.getGender());assertEquals(FIRST_NAME, customer.getFirstName());assertEquals(LAST_NAME, customer.getLastName());assertEquals(MIDDLE_NAME, customer.getMiddleName());assertEquals(customerDate, customer.getBecomeCustomer());});}}
}

这部分最吸引眼球的是 Builder 构建模式的手动实现,以及全新的断言方法 assertAll()JDK 8Lambda 表达式的结合。根据 assertAll 的签名,最后的断言逻辑还可以改写为如下模式,并且都能起到“执行所有断言、但不因某一个失败而中断后续断言的判定”的目的:

assertAll(() -> assertEquals(Gender.MALE, customer.getGender()),() -> assertEquals(FIRST_NAME, customer.getFirstName()),() -> assertEquals(LAST_NAME, customer.getLastName()),() -> assertEquals(MIDDLE_NAME, customer.getMiddleName()),() -> assertEquals(customerDate, customer.getBecomeCustomer())
);

本地 IDEA 的实测效果如下(起到了很好的分组效果):

Fig2.12

2.7 @Tag 注解

该注解是 JUnit 4@Category 的升级版,可通过 IDEpom.xml 配置,实现指定类别的测试类或测试方法的分组运行。

pom.xml 配置(推荐做法):

<build><plugins><plugin><artifactId>maven-surefire-plugin</artifactId><version>2.22.2</version><configuration><groups>individual</groups><excludedGroups>repository</excludedGroups></configuration></plugin>
</build>

IDEA 配置:

Fig2.4

原书截图界面和实测版本相差较大,新版 IDEA 已通过运行 配置文件 来完成相关设置。根据实测情况,Tags 标签可用 |& 等符号实现多个标签的组合运行(分别表示 )。特别地,对于 的情况还有两种写法:

// version 1
@Tag("individual")
@Tag("repository")
public class CustomerTest {// snip
}// version 2
@Tags({@Tag("individual"), @Tag("repository")})
public class CustomerTest {// snip
}

其中第二种的可读性更好。启用 @Tag 注解后,执行命令 mvn test 将只对指定了标签、且明确设置参与测试的单元测试用例才会最终执行。由于无法保证运行测试的人都使用 IDEA,因此更推荐使用 pom.xml 来配置 Tag 标签。

2.8 断言方法

新版 JUnit 5 提供了大量的断言方法,并支持 Java 8 的函数式声明提高测试性能。常见的几种有:

断言方法功能
assertAll断言所有提供的可执行对象都不会抛出异常,参数类型为 org.junit.jupiter.api.function.Executable 型对象或对象数组。
assertArrayEquals断言预期数组与实际数组相等。
assertEquals断言期望值与实际值相等。
assertX(..., String message)当断言失败时,向测试框架提供指定消息的断言。
assertX(..., Supplier<String> msgSupplier)当断言失败时,向测试框架提供指定消息的断言。报错后的消息提示会通过 msgSupplier 延迟获取。

此外,JUnit 4 中的 assertThat 断言在新版中被移除,该断言由 JUnit 第三方辅助框架 Hamcrest 重新实现,更加灵活且符合 Java 8 特性。

关于 Hamcrest 框架

该框架是辅助编写 JUnit 测试用例的第三方工具框架,内置了大量可读性极强的断言方法和辅助工具(各种 matcher 匹配器)。其名称 Hamcrest 就是 matchers 各字母变位后的组合单词,以突出其灵活实用的断言特性。

2.9 新版超时断言

对于超时场景下的断言测试,JUnit 5 提供了两种超时机制:

  • 超时后立即停止测试,不等待可执行的目标代码最终完成(使用 assertTimeout 断言);
  • 超时后继续执行测试,直到可执行的目标代码最终完成(使用 assertTimeoutPreemptively 断言);
class AssertTimeoutTest {private SUT systemUnderTest = new SUT("Our system under test");@Test@DisplayName("A job is executed within a timeout")void testTimeout() throws InterruptedException {systemUnderTest.addJob(new Job("Job 1"));assertTimeout(ofMillis(500), () -> systemUnderTest.run(200));}@Test@DisplayName("A job is executed preemptively within a timeout")void testTimeoutPreemptively() throws InterruptedException {systemUnderTest.addJob(new Job("Job 1"));assertTimeoutPreemptively(ofMillis(500), () -> systemUnderTest.run(200));}
}

assertTimeout() 超时后的报错信息的句式为:execution exceeded timeout of 100 ms by 193 ms.

assertTimeoutPreemptively() 超时后的报错信息的句式为:execution timed out after 100 ms.

2.10 需要抛出异常的断言测试

JUnit 5 还对需要抛异常的应用场景提供了便捷的断言方法。既可以直接书写 assertThrows() 断言,也可以通过该断言返回的 Throwable 对象作进一步断言,例如断言异常原因是否为指定的内容等。

实测代码如下:

class AssertThrowsTest {private SUT systemUnderTest = new SUT("Our system under test");@Test@DisplayName("An exception is expected")void testExpectedException() {assertThrows(NoJobException.class, systemUnderTest::run);}@Test@DisplayName("An exception is caught")void testCatchException() {Throwable throwable = assertThrows(NoJobException.class, () -> systemUnderTest.run(1000));assertEquals("No jobs on the execution list!", throwable.getMessage());}
}

2.11 假设断言

应用场景:满足某种前提条件后,方可执行后续的断言测试;否则直接跳过该断言的执行。

示例代码:

class AssumptionsTest {private static String EXPECTED_JAVA_VERSION = "1.8";private TestsEnvironment environment = new TestsEnvironment(new JavaSpecification(System.getProperty("java.vm.specification.version")),new OperationSystem(System.getProperty("os.name"), System.getProperty("os.arch")));private SUT systemUnderTest = new SUT();@BeforeEachvoid setUp() {assumeTrue(environment.isWindows());}@Testvoid testNoJobToRun() {assumingThat(() -> environment.getJavaVersion().equals(EXPECTED_JAVA_VERSION),() -> assertFalse(systemUnderTest.hasJobToRun()));}@Testvoid testJobToRun() {assumeTrue(environment.isAmd64Architecture());systemUnderTest.run(new Job());assertTrue(systemUnderTest.hasJobToRun());}
}

其中,L12L18L24 均为假设断言,如果该行假设不成立,则后续断言均不会执行。

(未完待续)

http://www.dtcms.com/a/504172.html

相关文章:

  • 微信公众号商城怎么开通株洲seo快速排名
  • 摩尔信使MThings网络性能实测
  • 国外网站兼职做效果图网站推广目标是什么
  • 企业建设网站的目的是做直播的视频在线观看网站
  • 色一把做最好网站福田欧曼银河报价
  • 新奇特:汉字句子中的暗物质和暗能量
  • 租用的网站空间的缺点免费ppt课件下载网站
  • 使用node Express 框架框架开发一个前后端分离的二手交易平台项目。
  • 如何统一管理多台电脑的基础系统设置?
  • 【算法】day8 二分查找+前缀和
  • 力扣160:相交链表
  • 用c做网站哈尔滨个人优化排名
  • 南部 网站 建设面试网站建设的问题
  • 从RNN到Transformer:深度学习架构革命
  • 【从0开始学习Java | 第23篇】动态代理
  • 公司营销型网站建设策划书wordpress 2019主题
  • C++--- volatile 关键字 禁止寄存器缓存与编译器层面的指令重排
  • 网站建站的具体流程什么平台可以免费打广告
  • HTTP相关知识点
  • Redis 未授权访问漏洞全解析:从原理到突破
  • 龙华做网站公司快速排名程序
  • 用eclipse做网站开发代做网站推广的公司
  • 企业级RAG落地思考
  • 验证用户登录的两种方式
  • 笔试-精准核酸检测
  • 知识就是力量——制作一个红外计数器
  • 做网站如何大众汽车网站建设
  • 【Linux笔记】网络部分——应用层自定义协议与序列化
  • 上海招聘网站排名米方科技网站建设
  • 佛山网站建设企业推荐房地产交易网站模版