Junit执行源码分析,junit是怎么跑起来的(二)

news2025/7/11 14:59:37

接上一篇【Junit执行源码分析,junit是怎么跑起来的】 https://blog.csdn.net/Aqu415/article/details/127494898 这里我们接着分析

org.junit.runner.JUnitCore#run(org.junit.runner.Runner)

这个方法

public Result run(Runner runner) {
        Result result = new Result();
        RunListener listener = result.createListener();
        notifier.addFirstListener(listener);
        try {
            notifier.fireTestRunStarted(runner.getDescription());
            // @A
            runner.run(notifier);
            notifier.fireTestRunFinished(result);
        } finally {
            removeListener(listener);
        }
        return result;
    }

@A:执行runer的run方法,会执行我们的待测试目标方法

上一篇说到
runner是 org.junit.internal.builders.AllDefaultPossibilitiesBuilder#runnerForClass得到的返回对象:

    public Runner runnerForClass(Class<?> testClass) throws Throwable {
        List<RunnerBuilder> builders = Arrays.asList(
                ignoredBuilder(),
                annotatedBuilder(),
                suiteMethodBuilder(),
                junit3Builder(),
                junit4Builder());

        for (RunnerBuilder each : builders) {
            Runner runner = each.safeRunnerForClass(testClass);
            if (runner != null) {
                return runner;
            }
        }
        return null;
    }

junit默认提供了几种Runner,比如听过的Junit3和熟悉的Junit4(其他的没听过 哈哈);
这里会决定返回哪一种 Runner;
从设计模式上来说这里运用的策略模式:每一种runner会根据目标测试类判解析是否需要自己来处理,如果是由自己来处理则返回一个Runner类;就好像说:嗯,你是我的菜,并把菜装在篮子里返回

举个例,我们看看 JUnit3Builder 是怎么判的该类是自己的菜的

public class JUnit3Builder extends RunnerBuilder {
    @Override
    public Runner runnerForClass(Class<?> testClass) throws Throwable {
        if (isPre4Test(testClass)) {
            return new JUnit38ClassRunner(testClass);
        }
        return null;
    }

    boolean isPre4Test(Class<?> testClass) {
        return junit.framework.TestCase.class.isAssignableFrom(testClass);
    }
}

如果类上标注了 @TestCase注解,那么这个类就会由JUnit3执行

**我们看看JUnit4Builder **

public class JUnit4Builder extends RunnerBuilder {
    @Override
    public Runner runnerForClass(Class<?> testClass) throws Throwable {
        return new BlockJUnit4ClassRunner(testClass);
    }
}

看代码JUnit4是一个兜底的方案,其他Runner不吃的菜全部由他来吃;嗯 了不起

BlockJUnit4ClassRunner

上面我们看到了JUnit4Builder 返回了一个BlockJUnit4ClassRunner对象;

在这里插入图片描述
BlockJUnit4ClassRunner继承了 ParentRunner,ParentRunner的run方法就是执行测试类方法的入口(上面标记@A的地方)。

org.junit.runners.ParentRunner#run
    @Override
    public void run(final RunNotifier notifier) {
        EachTestNotifier testNotifier = new EachTestNotifier(notifier,
                getDescription());
        try {
            Statement statement = classBlock(notifier);
            statement.evaluate();
        } catch (AssumptionViolatedException e) {
            testNotifier.addFailedAssumption(e);
        } catch (StoppedByUserException e) {
            throw e;
        } catch (Throwable e) {
            testNotifier.addFailure(e);
        }
    }
org.junit.runners.ParentRunner#classBlock
    protected Statement classBlock(final RunNotifier notifier) {
        // @B
        Statement statement = childrenInvoker(notifier);
        // @C
        if (!areAllChildrenIgnored()) {
            statement = withBeforeClasses(statement);
            statement = withAfterClasses(statement);
            statement = withClassRules(statement);
        }
        return statement;
    }

@B:找到标记了 @Test注解的方法
@C:把测试类里标注了 @BeforeClass(静态方法) 、@AfterClass(静态方法)等注解的方法找到并包装成 Statement对象,设计模式应该属于责任链模式,形成一个链式数据结构

org.junit.runners.BlockJUnit4ClassRunner#runChild

跟了一圈代码最终方法执行到
org.junit.runners.BlockJUnit4ClassRunner#runChild

    @Override
    protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
        Description description = describeChild(method);
        // @A
        if (isIgnored(method)) {
            notifier.fireTestIgnored(description);
        } else {
         // @B
            runLeaf(methodBlock(method), description, notifier);
        }
    }

@A:被忽略的方法,不被执行
@B:org.junit.runners.BlockJUnit4ClassRunner#methodBlock

    protected Statement methodBlock(FrameworkMethod method) {
        Object test;
        try {
            test = new ReflectiveCallable() {
                @Override
                protected Object runReflectiveCall() throws Throwable {
                    return createTest();
                }
            }.run();
        } catch (Throwable e) {
            return new Fail(e);
        }

        Statement statement = methodInvoker(method, test);
        statement = possiblyExpectingExceptions(method, test, statement);
        statement = withPotentialTimeout(method, test, statement);
        statement = withBefores(method, test, statement);
        statement = withAfters(method, test, statement);
        statement = withRules(method, test, statement);
        return statement;
    }

这里跟上面ParentRunner行为差不多,会把目标类里标注了 @Before、@After的方法和目标方法串联起来,这里区别的是:ParentRunner是把标注了@BeforeClass、和@AfterClass的静态方法串联起来。

todo~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/38509.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智慧监狱解决方案-最新全套文件

智慧监狱解决方案-最新全套文件一、建设背景二、思路架构三、建设方案四、获取 - 智慧监狱全套最新解决方案合集一、建设背景 “智慧监狱”是“数字法治、智慧司法”信息系统建设的重要组成部分&#xff0c;其主要内容是在现有监狱信息建设的基础上&#xff0c;充分利用大数据…

【机器学习】拉格朗日对偶性

有任何的书写错误、排版错误、概念错误等&#xff0c;希望大家包含指正。 拉格朗日对偶性 在求解最优化问题中&#xff0c;拉格朗日乘数法&#xff08;Lagrange Multiplier&#xff09;和 KKT&#xff08;Karush Kuhn Tucker&#xff0c;三个人名&#xff09;条件是两种最常用…

高性能零售IT系统的建设07-通过一次重大危机感受Redis从使用到失智到理性的治理

介绍 在2020年年初我接手的一座“屎山”里含有Redis框架和机制&#xff0c;它使用的是sentinel模式。其实sentinel模式并不是重点&#xff0c;按照我的经验&#xff0c;每天单店10万单也一样可以使用Redis Sentinel。只有到达新浪微博啦、头条啦这种大厂才有必要去架设redis cl…

Linux进程替换

进程替换 假如操作系统正在执行某一个程序&#xff0c;我们可以利用程序替换函数指定一个新的程序&#xff0c;让操作系统去执行我们新指定的程序。也就是这样一种情形下&#xff0c;我们fork一个进程&#xff0c;如果fork成功&#xff0c;子进程会和父进程执行相同的代码&…

基于springboot+vue的社区健康码管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

Hive数据操纵语言-DML(Load、insert、事务表)

1. Load加载数据 1.1 概述 主要为将数据文件移动到Hive表对应的位置&#xff0c;即复制、移动操作 1.2 语法 1.2.1 filepath 表示待移动数据的路径文件路径支持下面三种形式&#xff0c;要结合LOCAL关键字一起考虑&#xff1a; 相对路径&#xff0c;例如&#xff1a;projec…

音乐播放

在Qt5中使用Qt Multimedia 模块来实现多媒体应用&#xff08;音视频播放和控制&#xff0c;相机拍照。收音等&#xff09;。 使用多媒体模块时需要在pro文件中添加&#xff1a; QT multimedia QMediaPlayer&#xff08;播放音频&#xff09; 不追求低延迟的话使用QMediaPlaye…

作业练习3:类的继承

作业练习3&#xff1a;类的继承 面向对象程序设计(C) WHUT-CS 2022 Spring 源码传送门 传送门&#xff1a;https://pan.baidu.com/s/11KwE6tQzC_H-31AFgEWtOg?pwd1111 I.作业目的 本次实验主要在于学习使用C类继承机制实现程序功能。C中的举继承机制能够用于表示类之间的…

Crack:wodXMPP ActiveX 即时通讯组件

wodXMPP ActiveX 组件 XMPP组件&#xff0c;Jabber(ICQ MSN AIM Yahoo GTalk)即时通讯组件 wodXMPP 是 XMPP/Jabber&#xff08;可扩展消息传递和状态协议&#xff09;协议的客户端组件。它用于创建轻量级的消息传递客户端&#xff0c;并且除了 wodXMPP 之外不需要其他第 3 方要…

第八章《Java高级语法》第10节:注解

注解可以被理解为一种特殊的注释。普通注释是添加到代码中的人类语言,它可以提高程序的可读性。当源程序被编译为字节码之后,普通注释都会被去除掉,因为这些注释对代码的执行没有任何影响。因此,普通注释只能对代码的阅读者起到帮助。而注释则不同,注释可以对编译器和虚拟…

数字验证学习笔记——UVM学习1

一、类库地图 在SV模块中&#xff0c;验证环境整体的构建&#xff0c;是从底层模块的验证组件搭建到通信和激励生成这些元素无论是软件对象的创建、访问、修改、配置&#xff0c;还是组件之间的通信等都是通过用户自定义的方式来实现的。UVM验证方法学作为之前所有方法学的融合…

ubuntu22.04安装教程

1、选择语言 (默认) 2、取消安装更新 (默认) 3、选择键盘语言 (默认) 4、配置ip&#xff0c;可以直接选择dhcp&#xff0c;也可选择配置静态ip (默认) 5、配置代理 跳过不填写 6、设置镜像源 (默认) https://mirrors.aliyun.com/ubuntu/ 7、磁盘配置&#xff0c;默认即可 (默…

Java_接口使用实例

目录 给对象数组排序 按年龄来比较&#xff1a; 按名字来比较&#xff1a; 尝试自己实现一个 sort 方法 给对象数组排序 class Student {public String name;public int age;public int score;public Student(String name, int age, int score) {this.name name;this…

nginx基础篇

nginx基础篇nginx最小配置解析域名解析常用解析多租户解析Nginx虚拟主机域名配置ServerName匹配规则完整匹配通配符匹配通配符结束匹配正则匹配隧道式模型、网关、代理正向代理&反向代理网关隧道式模式反向代理反向代理一台服务器反向代理多台服务器负载均衡策略动静分离UR…

【微服务】SpringCloud断路器Hystrix

目录 一、断路器Hystrix 1、引入断路器 1.1、依赖 1.2、示例 2、传播安全上下文或使用Spring范围 3、健康指标 4、 Hystrix超时和RibbonClient 一、断路器Hystrix 较低级别的服务中的服务故障可能会导致级联故障&#xff0c;直至服务雪崩。在metrics.rollingStats.timeI…

五、Nacos

文章目录一、安装nacos1.压缩包下载地址2.nacos 中修改端口(8848 端口被占用需要修改)3.启动 nacos&#xff1a;二、nacos项目环境配置三、nacos服务分级存储模型四、NacosRule 实现负载均衡五、服务实例的权重设置六、nacos注册中心一、安装nacos 1.压缩包下载地址 https://…

LeetCode HOT 100 —— 33.搜索旋转排序数组

题目 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nums[1], ……

Hive之存储和压缩

Hive系列 第十章 存储和压缩 10.1 首先看一下Hadoop中的压缩 10.1.1 基本概念 1、概念 压缩是一种通过特定的算法来减小计算机文件大小的机制。这种机制是一种很方便的发明&#xff0c;尤其是对网络用户&#xff0c;因为它可以减小文件的字节总数&#xff0c;使文件能够通过…

Linux-yum

Linux下的开发工具即配置基本都要自己手动&#xff0c;和Windows一键式安装相比&#xff0c;Linux软件的安装要复杂很多。 centos 7下&#xff0c;基本的安装方式有三种&#xff1a; 1.源码安装——挺常用的&#xff0c;但是复杂&#xff0c;对初学者来说可以忽略。 2.rpm包安…

FFmpeg的makefile逻辑分析

在开始分析之前&#xff0c;讲一个 makefile 的调试技巧&#xff0c;推荐阅读《如何调试MAKEFILE变量》 make -f Makefile -f vars.mk HOSTPROGS这里我对 vars.mk 做了点修改&#xff0c;因为源 vars.mk 没处理特殊字符&#xff0c;直接 echo 会报错。ffmpeg 的 makefile 的变…