浅解 Junit 4 第五篇:IgnoredBuilder 和 RunnerBuilder

背景

浅解 Junit 4 第四篇:类上的 @Ignore 注解 一文中,我们初步探讨了 测试类上的 @Ignore 注解是如何起作用的,要点如下图所示 👇

新的问题来了, org.junit.internal.builders.IgnoredClassRunner \text{org.junit.internal.builders.IgnoredClassRunner} org.junit.internal.builders.IgnoredClassRunner 又是怎么构建出来的呢?本文会对 IgnoredClassRunner 的构建过程进行探讨。

要点

  • 可以使用构建者(builder)设计模式来构建 Runner
    • Runner 的构建者(builder)是 RunnerBuilder
    • RunnerBuilder 是抽象类,我们需要用它的子类来执行具体的构建逻辑
  • 类上有 @Ignore 的测试类,它对应的 RunnerIgnoredClassRunner,而IgnoredClassRunner 对应的构建者(builder)是 IgnoredBuilder

正文

项目结构

探讨本文的问题,不需要在项目中加入新的 java 代码,项目中已有的代码在 浅解 Junit 4 第四篇:类上的 @Ignore 注解 一文中的 一个具体的例子 这一小节有具体的描述,这里就不赘述了。项目结构如下图所示(.idea/ 目录是 Intellij IDEA 生成的,可以忽略它)

IgnoredClassRunner 是如何构建的?

这里用到了 构建者(builder) 设计模式。用大白话说,就是对某个类 C \text{C} C 而言,我们不需要关心 C \text{C} C 具体是如何构建的,由专门的 Builder C \text{Builder}\text{C} BuilderC 来负责构建 C \text{C} C,我们只需要调用 Builder C \text{Builder}\text{C} BuilderC 里的方法(例如可能是 build(C c) 这样的方法)。生活中也有很多这样的例子。

  • 我们用真实的棋盘下棋时,不必关心棋盘具体是如何制作出来的。棋盘的制造商会负责处理好各种细节(可以把棋盘的制造商视为棋盘的 builder
  • 我们用电脑时,不必关心电脑具体是如何制造出来的。电脑的制造商会负责处理好各种细节(可以把电脑的制造商视为电脑的 builder
  • 我们做算法题时,不必关心题目是如何编出来的。命题者会负责处理好各种细节(可以把命题者视为题目的 builder
  • 我们看小说时,不必关心小说的情节是如何构思的。作者会负责处理好各种细节(可以把作者视为小说的 builder
  • ⋯ \cdots

IgnoredClassRunner 而言,它的构建者(builder)是 org.junit.internal.builders.IgnoredBuilder \text{org.junit.internal.builders.IgnoredBuilder} org.junit.internal.builders.IgnoredBuilder。而 IgnoredBuilder org.junit.runners.model.RunnerBuilder \text{org.junit.runners.model.RunnerBuilder} org.junit.runners.model.RunnerBuilder 的子类。RunnerBuilderIgnoredBuilder 的简要类图如下 👇

IgnoredBuilder 中的 runnerForClass((Class<?>) 的代码如下

java 复制代码
@Override
public Runner runnerForClass(Class<?> testClass) {
    if (testClass.getAnnotation(Ignore.class) != null) {
        return new IgnoredClassRunner(testClass);
    }
    return null;
}

其逻辑比较直观

  • 如果 testClass 对应的类上有 @Ignore 注解,则返回对应的 IgnoredClassRunner
  • 否则,返回 null

测试类,运行器(Runner),以及运行器的构建者(RunnerBuilder)三者之间的关系如下图所示

如果一个测试类 T 上带有 @Ignore 注解,那么此时测试类,运行器(Runner),以及运行器的构建者(RunnerBuilder)三者之间的关系如下图所示

其他

文中的"RunnerBuilderIgnoredBuilder 的简要类图"一图是如何绘制的?

我是用 PlantUML 画的,具体代码如下

puml 复制代码
@startuml
'https://plantuml.com/class-diagram

title <i>RunnerBuilder</i> 和 <i>IgnoredBuilder</i> 的简要类图

abstract class org.junit.runners.model.RunnerBuilder
class org.junit.internal.builders.IgnoredBuilder

org.junit.runners.model.RunnerBuilder <|-- org.junit.internal.builders.IgnoredBuilder

abstract class org.junit.runners.model.RunnerBuilder {
    +{abstract}Runner runnerForClass(Class<?> testClass) throws Throwable
}

class org.junit.internal.builders.IgnoredBuilder {
    +Runner runnerForClass(Class<?> testClass)
}

note right of org.junit.runners.model.RunnerBuilder::runnerForClass
这个方法的 <i>javadoc</i> 提到
Override to calculate the correct runner for a test class at runtime.
end note

note right of org.junit.internal.builders.IgnoredBuilder::runnerForClass
如果 <i>testClass</i> 对应的类上有 <i>@Ignore</i> 注解,
则此方法返回对应的 <i>IgnoredClassRunner</i>;
否则此方法返回 <i>null</i>
end note

caption 注意:图中只列出了本文关心的字段和方法

@enduml

文中的"测试类,运行器(Runner),以及运行器的构建者(RunnerBuilder)"一图是如何绘制的?

我是用 PlantUML 画的,具体代码如下

puml 复制代码
@startmindmap
'https://plantuml.com/mindmap-diagram

top to bottom direction

title 测试类,运行器(<i>Runner</i>),以及运行器的构建者(<i>RunnerBuilder</i>)

*[#Orange] 一个测试类 <i>T</i>
**[#lightgreen] 对应的 <i>Runner</i> 是 <i>Runner<sub>T</sub></i>
***[#lightblue] 用 <i>RunnerBuilder</i> 的某个子类来构建 <i>Runner<sub>T</sub></i>

legend right
橙色节点表示测试类
浅绿色节点表示 <i>Runner</i>
浅蓝色节点表示 <i>RunnerBuilder</i>
endlegend

@endmindmap

文中的"当测试类上有 @Ignore 注解时"一图是如何绘制的?

我是用 PlantUML 画的,具体代码如下

puml 复制代码
@startmindmap
'https://plantuml.com/mindmap-diagram

top to bottom direction

title 当测试类上有 <i>@Ignore</i> 注解时

*[#Orange]:一个带有 <i>@Ignore</i> 注解的测试类 <i>T</i>
(<b><i>T</i> 类上有 <i>@Ignore</i> 注解</b>);
**[#lightgreen] 对应的 <i>Runner</i> 是 <i>IgnoredClassRunner<sub>T</sub></i>
***[#lightblue]:对应的 <i>RunnerBuilder</i> 是 <i>IgnoredBuilder</i>
用 <i>IgnoredBuilder</i> 来构建 <i>IgnoredClassRunner<sub>T</sub></i>;


legend right
橙色节点表示测试类
浅绿色节点表示 <i>Runner</i>
浅蓝色节点表示 <i>RunnerBuilder</i>
endlegend
@endmindmap

参考资料

相关推荐
HokKeung14 小时前
Go 项目难测试,问题通常出在代码结构
单元测试·go
博观而约取厚积而薄发2 天前
Pytest 从入门到精通,一篇就够(超详细实战教程)
python·测试工具·单元测试·自动化·pytest
名字还没想好☜2 天前
用 Redis + Redisson 实现分布式锁:从踩坑到生产可用
java·redis·分布式·junit·分布式锁·redisson
gis开发之家2 天前
《Vue3 从入门到大神29篇》单元测试与 E2E 测试 —— 保障 Vue3 项目的质量
前端·javascript·vue.js·单元测试·前端框架·vue3
ipad协议源码2 天前
为何网站会出现的挂马?
junit·软件开发·开源源码
ysu_03142 天前
06 | 200个单元测试C项目也能TDD
c语言·单元测试·tdd
●VON2 天前
HarmonyKit | 鸿蒙开发展望:HarmonyKit 未来路线图与社区共建
华为·单元测试·harmonyos·鸿蒙
再玩一会儿看代码3 天前
JUnit 测试框架详解:从实际开发、业务测试到 Java 面试高频问题
java·经验分享·笔记·junit·面试
●VON3 天前
HarmonyKit | 鸿蒙新特性:HDS 沉浸光感与空间化视觉设计
华为·性能优化·单元测试·harmonyos·鸿蒙