浅解 Junit 4 第四篇:类上的 @Ignore 注解

背景

浅解 Junit 4 第二篇: Runner 和 ParentRunner 一文中,我们初步探讨了 JUnit 4 是如何找到并运行带有 @Test 注解的方法的。但有时候,代码还没有写好,测试类还不能成功运行,我们可以在测试类上添加 @Ignore 注解。那么类上的 @Ignore 注解是如何起作用的呢?本文会对这个问题进行探讨。

注意: @Ignore 注解也可以加在 方法 上,本文 不涉及 那样的情况。

要点

  • 对带有 @Ignore 注解的测试类 T 而言,它对应的 Runner 是 <math xmlns="http://www.w3.org/1998/Math/MathML"> org.junit.internal.builders.IgnoredClassRunner \text{org.junit.internal.builders.IgnoredClassRunner} </math>org.junit.internal.builders.IgnoredClassRunner
  • IgnoredClassRunner 中的 run(RunNotifier notifier) 方法不会运行任何测试,这样 T 中的所有测试就都被 ignore (忽略)了

正文

浅解 Junit 4 第二篇: Runner 和 ParentRunner 一文中,我们已经分析了 RunnerParentRunnerRunner (运行器)负责运行对应的测试,那么带有 @Ignore 注解的测试类是否也是由某个 Runner 来处理的呢?

一个具体的例子

我在本地创建了一个小项目来以便于学习 JUnit 4,这个项目中包含以下目录/文件(.idea 目录和 target 目录的内容均略去)

  • src/test/java/org/study 目录下的文件是

    • src/test/java/org/study/SimpleCalculatorTest.java
  • src/main/java/org/example 目录下的文件是

    • src/main/java/org/example/SimpleCalculator.java
  • pom.xml (在项目顶层)

执行以下 shell 命令,就可以生成上述目录/文件(文件为空,下文列出了 SimpleCalculatorTest.java/SimpleCalculator.java/pom.xml 的内容,可以手动复制粘贴过去)

bash 复制代码
mkdir junit-study
cd junit-study

mkdir -p src/main/java/org/example/
mkdir -p src/test/java/org/study/

touch src/main/java/org/example/SimpleCalculator.java
touch src/test/java/org/study/SimpleCalculatorTest.java
touch pom.xml

src/main/java/org/example/SimpleCalculator.java 文件的内容如下 ⬇️

java 复制代码
package org.example;

/**
 * A simple calculator for integer addition & subtraction operation
 */
public class SimpleCalculator {
    /**
     * TODO: implement the logic for adding two integer numbers
     */
    public int add(int a, int b) {
        return 0;
    }

    /**
     * TODO: implement the logic for subtracting one integer number from another one
     */
    public int minus(int a, int b) {
        return 0;
    }
}

src/test/java/org/study/SimpleCalculatorTest.java 文件的内容如下 ⬇️

java 复制代码
package org.study;

import org.example.SimpleCalculator;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.JUnitCore;

@Ignore
public class SimpleCalculatorTest {

    private final SimpleCalculator calculator = new SimpleCalculator();

    @Test
    public void testAdd() {
        Assert.assertEquals(2, calculator.add(1, 1));
    }

    @Test
    public void testMinus() {
        Assert.assertEquals(1, calculator.minus(2, 1));
    }

    public static void main(String[] args) {
        JUnitCore.runClasses(SimpleCalculatorTest.class);
    }
}

pom.xml 文件的内容如下 ⬇️

xml 复制代码
<?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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>junit-study</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>25</maven.compiler.source>
        <maven.compiler.target>25</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

SimpleCalculator 的类图如下

由于 SimpleCalculator 中的 add(...) 方法和 minus(...) 方法的逻辑尚未实现,所以对应的单元测试无法通过,我们可以在 SimpleCalculatorTest 类上添加 @Ignore 注解,如下图所示 ⬇️

类上的 @Ignore 注解是如何起作用的?

SimpleCalculatorTest 类上添加 @Ignore 注解之后,发生了什么呢?带有 @Ignore 注解的测试类,它所对应的 Runner 会是一个特殊的类 ⬇️ <math xmlns="http://www.w3.org/1998/Math/MathML"> org.junit.internal.builders.IgnoredClassRunner \text{org.junit.internal.builders.IgnoredClassRunner} </math>org.junit.internal.builders.IgnoredClassRunner

我们可以在它的构造函数里打个断点(断点的位置如下图所示)

之后 debug SimpleCalculatorTestmain 方法。在断点处,可以看到 testClass 参数(也就是待测试的类的 class 对象)的值为 <math xmlns="http://www.w3.org/1998/Math/MathML"> org.study.SimpleCalculatorTest.class \text{org.study.SimpleCalculatorTest.class} </math>org.study.SimpleCalculatorTest.class

IgnoredClassRunnerRunner 的子类。之前我们介绍过 Runner 的另一个子类 ParentRunner(当我们认为 Runner 具有"亲子结构"时,就可以使用 ParentRunner)。下方的类图中同时展示了 ParentRunnerIgnoredClassRunner ⬇️

IgnoredClassRunnerrun(RunNotifier) 方法中并没有运行任何测试,只是调用了 RunNotifier 的某个方法(从而通知各个 listener 这个测试被 ignore 了) ⬇️

其他

1. 文中的"测试类 T 上的注解 @Ignore 是如何起作用的?"一图是如何绘制的?

我用了 PlantUML 来画那张图,具体的代码如下

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

title 测试类 <i>T</i> 上的注解 <i>@Ignore</i> 是如何起作用的?

*[#lightgreen]:测试类 <i>T</i> 上有 <i>@Ignore</i> 注解
(<i>@Ignore</i> 注解在类上);
**[#lightgreen]:测试类 <i>T</i> 对应的 <i>Runner<sub>T</sub></i> 是
<i>org.junit.internal.builders.IgnoredClassRunner</i>;
***[#lightgreen]:而 <i>Runner<sub>T</sub></i> 的 <i>run(RunNotifier notifier)</i> 方法
<b>不会</b> 运行任何测试;



@endmindmap

2. 文中的"org.example.SimpleCalculator 的类图"是如何绘制的?

我是先用 Intellij IDEA (Community Edition) 里的 PlantUML Parser 插件(如下图所示)为 SimpleCalculator 这个类生成了基本的类图,然后又手动添加了 note,title 等内容。

用到的代码如下

puml 复制代码
@startuml
title <i>org.example.SimpleCalculator</i> 的类图

class org.example.SimpleCalculator {
+ int add(int,int)
+ int minus(int,int)
}

note left of SimpleCalculator::add
<i>add(...)</i> 方法的功能尚未实现
end note

note right of SimpleCalculator::minus
<i>minus(...)</i> 方法的功能尚未实现
end note

footer 这张图是在 <b>PlantUML Parser</b> 插件的帮助下绘制的 (图中的 <i>note</i> 是我自己添加的)

@enduml

3. 文中的"ParentRunnerIgnoredClassRunner 的继承体系"一图是如何绘制的?

我用了 PlantUML 来画那张图,具体的代码如下

puml 复制代码
@startuml
title <i>ParentRunner</i> 和 <i>IgnoredClassRunner</i> 的继承体系

org.junit.runner.Runner <|-- org.junit.runners.ParentRunner
org.junit.runner.Runner <|-- org.junit.internal.builders.IgnoredClassRunner

abstract class org.junit.runner.Runner {
    +{abstract} void run(RunNotifier notifier)
}

abstract class org.junit.runners.ParentRunner<T> {
    -final TestClass testClass
    #{abstract} List<T> getChildren()
    +void run(final RunNotifier notifier)
}

class org.junit.internal.builders.IgnoredClassRunner {
    -final Class<?> clazz
    +void run(RunNotifier notifier)
}


footer 注意: 图中略去了本文不关心的方法/字段/接口 

@enduml
相关推荐
西门吹雪分身2 小时前
K8S之Pod生命周期
java·kubernetes·k8s
hrhcode2 小时前
【Netty】一.Netty架构设计与Reactor线程模型深度解析
java·spring boot·后端·spring·netty
亓才孓2 小时前
[Spring MVC]BindingResult
java·spring·mvc
会算数的⑨2 小时前
Spring AI Alibaba 学习(三):Graph Workflow 深度解析(下篇)
java·人工智能·分布式·后端·学习·spring·saa
chilavert3182 小时前
技术演进中的开发沉思-367:锁机制(上)
java·开发语言·jvm
BigGGGuardian2 小时前
写了个 Spring Boot 防重复提交的轮子,已发到 Maven Central
java
hewence12 小时前
协程间数据传递:从Channel到Flow,构建高效的协程通信体系
android·java·开发语言
哈库纳2 小时前
dbVisitor 利用 queryForPairs 让键值查询一步到位
java·后端·架构
野犬寒鸦2 小时前
CompletableFuture 在 项目实战 中 创建异步任务 的核心优势及使用场景
java·服务器·后端·性能优化