单元测试运行与测试替身对比及后续学习建议
1. 使用不同工具运行单元测试
1.1 使用 IntelliJ IDEA 运行测试
IntelliJ IDEA 自带 TestNG - J 插件,可识别 TestNG 测试。运行测试的方式有两种:
-
鼠标操作
:
- 运行单个测试类:右键点击选定的测试类(如
MoneyTest
),选择“Run ‘MoneyTest’”。
- 运行多个测试:在项目树视图中,右键点击
src/test/java
目录(或包含测试的任何包),选择相应的“Run …”选项。
- 运行单个测试方法:右键点击该方法,选择“Run ‘MoneyTest’”。
-
键盘操作
:
- 运行所选类的所有测试:确保测试类在编辑器中处于焦点状态,将光标置于任何测试方法之外,按下
CTRL + SHIFT + F10
。
- 运行特定测试方法:将光标置于该方法上,使用相同组合键
CTRL + SHIFT + F10
。
- 重新运行相同测试:按下
SHIFT + F10
。
1.1.1 使用 IntelliJ IDEA 调试测试
调试测试也有多种方式:
- 右键点击测试类、测试包或测试方法,选择“Debug …”选项。
- 使用
ALT + SHIFT + F9
键。
- 重新运行相同调试会话:按下
SHIFT + F10
。
1.2 使用 Gradle 运行测试
Gradle 是强大且复杂的构建工具。要使用 Gradle 运行 TestNG 测试,需告知它查找 TestNG 测试,并为
testCompile
范围提供 TestNG 依赖。以下是一个基本的
build.gradle
文件示例:
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
testCompile 'org.testng:testng:6.4'
}
test {
useTestNG()
}
上述代码解释如下:
-
apply plugin: 'java'
:告诉 Gradle 准备编译 Java 类。
-
repositories { mavenCentral() }
:定义用于下载依赖项的仓库(这里是 Maven 中央仓库,包含 TestNG JAR 文件)。
-
dependencies { testCompile 'org.testng:testng:6.4' }
:定义用于测试编译(和执行)的库(这里是
testng - 6.4.jar
)。
-
test { useTestNG() }
:指示 Gradle 查找 TestNG 测试类以运行测试。
运行测试的步骤如下:
1. 将上述
build.gradle
文件放在应用程序的根目录。
2. 在命令行执行
gradle test
。示例输出如下:
>gradle test
:first_test:compileJava
:first_test:processResources
:first_test:classes
:first_test:compileTestJava
:first_test:processTestResources
:first_test:testClasses
:first_test:test
BUILD SUCCESSFUL
若要获取更多信息,可使用
-i
开关,或编写自己的监听器。若测试失败,Gradle 会打印错误消息。若要运行单个测试,使用
gradle -Dtest.single=MoneyTest test
语法。
1.2.1 使用 TestNG 监听器和报告器与 Gradle
可在构建脚本的测试配置部分传递监听器和报告器类的全限定名,让 TestNG 使用它们。示例如下:
test {
useTestNG()
options {
listeners << 'com.practicalunittesting.DotTestListener',
listeners << 'fully.qualified.path.to.ExcelReporter'
}
}
1.2.2 向 Gradle 的测试类路径添加 JAR
若测试需要额外库,需将其添加到
testCompile
范围。示例如下:
dependencies {
testCompile 'org.testng:testng:6.4'
testCompile 'org.hamcrest:hamcrest-all:1.1'
testCompile 'com.practicalunittesting.listeners:1.0'
}
1.3 使用 Maven 运行测试
使用 Maven 运行测试,需了解 Maven Surefire 插件、Maven Surefire 报告插件和 Maven 站点插件的文档。以下是一个基本的 Maven 构建脚本示例:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.practicalunittesting</groupId>
<artifactId>first-test</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.4</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
运行测试的步骤如下:
1. 确保理解 Maven 的基本概念(如生命周期)。
2. 在命令行执行
mvn test
。示例输出如下:
[INFO] -------------------------------------------------------------------
[INFO] Building first-test 1.0-SNAPSHOT
[INFO] -------------------------------------------------------------------
[INFO]
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running TestSuite
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.295 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] -------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] -------------------------------------------------------------------
若测试失败,Maven 会在控制台打印错误消息。测试结果以文本和 XML 格式保存在
target/surefire - reports
目录。若需要更易读的报告,可使用 Maven Surefire 报告插件或 Maven 站点插件生成 HTML 报告。
1.3.1 使用 TestNG 监听器和报告器与 Maven
可编写自己的监听器和报告器,并让 Maven 使用它们。以下是 Maven Surefire 插件配置示例:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12</version>
<configuration>
<properties>
<property>
<name>listener</name>
<value>com.practicalunittesting.DotTestListener</value>
</property>
<property>
<name>reporter</name>
<value>com.practicalunittesting.ExcelReporter</value>
</property>
</properties>
</configuration>
</plugin>
1.3.2 向 Maven 的测试类路径添加 JAR
若要向测试类路径添加其他库,需像指定 TestNG 依赖一样指定它们。示例如下:
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.practicalunittesting</groupId>
<artifactId>listeners</artifactId>
<version>1.0</version>
<scope>test</scope>
</dependency>
</dependencies>
确保使用
test
范围,以便 Maven 将它们添加到测试类路径。
运行测试工具对比表格
| 工具 | 配置方式 | 运行命令 | 报告处理 | 监听器和报告器配置 |
|---|---|---|---|---|
| IntelliJ IDEA | 自带 TestNG - J 插件 | 鼠标操作或键盘操作 | IDE 内查看 | 暂未提及 |
| Gradle |
编写
build.gradle
文件
|
gradle test
|
命令行查看,可使用
-i
开关获取更多信息
|
在
build.gradle
文件的
test
部分配置
|
| Maven |
编写
pom.xml
文件
|
mvn test
|
结果保存在
target/surefire - reports
目录,可生成 HTML 报告
|
在
pom.xml
的
maven - surefire - plugin
配置
|
运行测试流程图
graph LR
A[选择运行工具] --> B{IntelliJ IDEA}
A --> C{Gradle}
A --> D{Maven}
B --> B1[鼠标操作或键盘操作运行测试]
B --> B2[调试测试]
C --> C1[配置 build.gradle 文件]
C1 --> C2[执行 gradle test 命令]
C2 --> C3[查看测试结果]
D --> D1[配置 pom.xml 文件]
D1 --> D2[执行 mvn test 命令]
D2 --> D3[查看测试结果]
2. 测试替身:测试间谍与模拟对象的对比
2.1 不同的流程和断言者
测试间谍和模拟对象都用于验证被测系统(SUT)与依赖对象(DOCs)之间调用的正确性,但它们在测试流程和断言方式上有所不同。
2.1.1 测试间谍示例
// arrange
SomeClass sut = ...;
ClientDAO testSpyClientDAO = mock(ClientDAO.class);
sut.setClientDAO(testSpyClientDAO);
// act
sut.deleteClient(req, resp);
// assert
verify(testSpyClientDAO).deleteClient("1234");
测试间谍的测试流程清晰,分为三个阶段:
1.
安排(Arrange)
:创建 SUT 和测试间谍对象,并将测试间谍对象注入到 SUT 中。
2.
行动(Act)
:调用 SUT 的方法。
3.
断言(Assert)
:显式地验证测试间谍对象的方法调用。
2.1.2 模拟对象示例
// arrange
SomeClass sut = ...;
ClientDAO mockClientDAO = createMock(ClientDAO.class);
sut.setClientDAO(mockClientDAO);
// assert - part I
expect(mockClientDAO.deleteClient("1234"));
replay(mockClientDAO);
// act
sut.deleteClient(req, resp);
// assert - part II
verify(mockClientDAO);
模拟对象的断言阶段分为两个部分:
1.
设置期望(Assert - part I)
:在行动之前设置模拟对象的期望行为。
2.
验证期望(Assert - part II)
:在行动之后验证模拟对象的期望是否得到满足。
2.2 错误处理方式
- 模拟对象 :在方法执行过程中,如果任何方法调用不符合期望,测试会立即失败。
- 测试间谍 :在所有方法执行完毕后的验证阶段,如果发现方法调用不符合期望,测试才会失败。
测试间谍在断言消息中可能提供更详细的信息,因为它在所有方法执行完毕后进行验证。而模拟对象在运行时失败,可能会丢失一些信息。
2.3 存根功能
大多数人认为测试间谍也具有存根功能,例如 Mockito 框架为其测试间谍提供了存根功能。
2.4 宽容性
测试间谍通常比模拟对象更“宽容”,它允许指定要验证的交互,而忽略其他交互。例如,Mockito 测试间谍框架支持这种方式,避免过度指定测试。
然而,模拟框架通常更严格,但有些框架(如 EasyMock)支持两种测试风格。默认情况下,EasyMock 的模拟对象是“严格”的,但也允许使用“友好”的模拟对象,只验证选定的交互,类似于 Mockito 的测试间谍。
测试间谍与模拟对象对比表格
| 对比项 | 测试间谍 | 模拟对象 |
|---|---|---|
| 测试流程 | 遵循“安排 - 行动 - 断言”模式 | 断言阶段分为设置期望和验证期望两个部分 |
| 错误处理 | 所有方法执行完毕后验证,可能提供更详细信息 | 方法执行过程中不符合期望立即失败,可能丢失信息 |
| 存根功能 | 大多数支持 | 支持 |
| 宽容性 | 更宽容,可指定验证交互 | 通常更严格,但部分框架支持两种风格 |
测试间谍与模拟对象对比流程图
graph LR
A[测试类型] --> B{测试间谍}
A --> C{模拟对象}
B --> B1[安排 SUT 和测试间谍]
B1 --> B2[行动:调用 SUT 方法]
B2 --> B3[断言:验证测试间谍方法调用]
C --> C1[安排 SUT 和模拟对象]
C1 --> C2[设置模拟对象期望]
C2 --> C3[行动:调用 SUT 方法]
C3 --> C4[验证模拟对象期望]
3. 后续学习建议
3.1 深入学习测试工具
- 详细阅读 TestNG 和 Mockito 的文档,查找本书未涵盖的内容。
- 关注新版本的发布公告,了解新功能。
3.2 掌握开发工具
- 熟练掌握 IDE、构建工具和命令行,用于编写和执行测试。
3.3 学习其他测试工具
- 学习新语言时,了解为该语言设计的测试工具。
3.4 开始实践 TDD
- 若尚未开始,尝试进行测试驱动开发(TDD)。
- 与更有经验的同行进行结对编程。
- 尝试使用 IDE 插件,使编写测试更有趣。
3.5 迈向 BDD
- 掌握 TDD 后,学习行为驱动开发(BDD)。
3.6 学习应用测试
- 阅读相关书籍,深入了解可测试软件的开发。
- 开始编写集成测试和端到端测试。
3.7 处理遗留代码
- 若经常处理遗留代码,学习相关知识和技巧。
3.8 自动化测试和持续集成
- 建立自动化测试流程,使用构建工具和持续集成服务器。
- 若团队已使用,追求持续交付。
3.9 分享知识和经验
- 参加社区活动,如代码撤退会议和代码练习。
- 在 GitHub 等平台分享代码。
- 在 RefactorMyCode.com 或 StackOverflow 等网站寻求指导和反馈。
- 参与开源项目,与他人合作开发。
后续学习建议列表
- 深入学习测试工具
- 掌握开发工具
- 学习其他测试工具
- 开始实践 TDD
- 迈向 BDD
- 学习应用测试
- 处理遗留代码
- 自动化测试和持续集成
- 分享知识和经验
后续学习建议流程图
graph LR
A[学习起点] --> B[深入学习测试工具]
A --> C[掌握开发工具]
A --> D[学习其他测试工具]
B --> E[实践 TDD]
E --> F[迈向 BDD]
C --> G[学习应用测试]
D --> H[处理遗留代码]
G --> I[自动化测试和持续集成]
I --> J[分享知识和经验]
通过以上内容,我们了解了使用不同工具运行单元测试的方法,对比了测试间谍和模拟对象的差异,并给出了后续学习的建议。希望这些信息能帮助你在单元测试的道路上不断前进。
超级会员免费看
566

被折叠的 条评论
为什么被折叠?



