Junit 3.8.1 源码分析(一)
写在前面:本文基于Junit3.8.1版本,因为这是我第一次进行源码学习,先从简单的源码开始学起
1. 示例代码
1.1 准备工作
- 下载Junit3.8.1的JAR包
- 需要下载
junit-3.8.1-sources.jar和junit-3.8.1.jar,前者是源码包,后者是项目中需要使用的Jar包;
1.2 项目中导入Junit相关jar包
- 使用Eclipse,新建项目
test; test右键,选中properties


1.3 编写示例代码
- JUnit4之前,JUnit明确要求测试方法名以"test"开头;
- JUnit 测试类需要继承 "TestCase";
// SampleCalculator.java,需要测试的类
public class SampleCalculator{
// 加法
private int add(int a, int b){
return a + b;
}
// 乘法
public int multiply(int a, int b){
return a * b;
}
//除法
public double divide(int a, int b){
return a/b;
}
}
// 编写测试类,该类需要继承 TestCase
public class TestSample extends TestCase{
private SampleCalculator cal = null;
protected void setUp() throws Exception{
super.setUp();
// 每个测试方法执行前,重新new一个对象,避免测试用例之间的依赖
cal = new SampleCalculator():
System.out.println("在每个测试方法执行前执行 ---setUp...");
}
// 测试源代码的私有方法
public void testAdd(){
System.out.println("测试方法testAdd...");
try{
// 使用反射,进行私有方法的调用
Class<SampleCalculator> clazz = SampleCalculator.class;
Method method = clazz.getDeclaredMethod("add", new Class[] { Integer.TYPE, Integer.TYPE});
method.setAccessible(true);
Object obj = method.invoke(cal, new Object[]{1, 2});
Assert.assertEquals(3, obj);
}catch(Exception e){
Assert.fail();
}
}
// 测试乘法
public void testMultiply(){
System.out.println("测试方法testMultiply...");
Assert.assertEquals.(3, cal.multiply(1, 2));
}
// 测试除法
public void testDivice(){
System.out.println("测试方法testDivide...");
Assert.assertEquals(2, cal.divide(1, 0));
}
@Override
protected void tearDown() throws Exception{
super.tearDown();
cal = null; // 在每个测试方法执行后,主动销毁对象
System.out.println("在每个测试方法执行后执行--tearDown...\n");
}
// main方法调用
public static void main(String[] args){
// 以文字输出的方式,显示运行结果
junit.textui.TestRunner.run(TestSample.class);
// 以图形化界面的方式,显示运行结果
// junit.swingui.TestRunner.run(TestSample.class);
// 以图形化界面的方式,显示运行结果
// junit.awtui.TestRunner.run(TestSample.class);
}
}

备注
- Failures:表示测试的期待结果与程序运行结果不相符;
- Errors: 表示测试程序执行过程中,抛出了异常;
2. JUnit运行流程(DEBUG模式运行)
- JUnit的完整生命周期分为三个阶段:初始化阶段,运行阶段和结果捕捉阶段
2.1 初始化阶段(创建TestCase及TestSuite)



- 图中红框处,采用了
Composite Pattern;while循环第一次,获取TestSample中的方法,
第二次循环,获取其父类TestCase中的方法:superClass = superClass.getSuperclass();;
// TestSuite.java
public class TestSuite implements Test{
private Vector fTests = new Vector(10);
private String fName;
...(略)
// 将符合条件的测试方法转化为TestCase,并存入到集合中
public void addTestMethod(Method m, Vector names, Class theClass){
String name = m.getName();
if(names.contains(name))
return;
// 判断是否是公共方法
if(!isPublicTestMethod(m)){
// 判断是否是测试方法
if(isTestMethod(m))
addTest(warning("Test method isn't public: "+m.getName()));
return;
}
names.addElement(name);
// 将testXXX方法转化为 TestCase
addTest(createTest(theClass, name));
}
public void addTest(Test test){
fTests.addElement(test);
}
// 判断是否是公共方法
public boolean isPublicTestMethod(Method m){
return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
}
// 判断是否是测试方法
// 1. 名称以"test"开头
// 2. 无参数,无返回值
public boolean isTestMethod(Method m){
String name = m.getName();
Class[] parameters = m.getParameterTypes();
Class returnType = m.getReturnType();
return parameters.length == 0 && name.startWith("test") && returnType.equals(Void.TYPE);
}
// 根据testXXX名称,创建对应的TestCase
static public Test createTest(Class theClass, String name){
Constructor constructor;
try{
constructor = getTestConstructor(theClass);
}catch(NoSuchMethodException e){
...(略)
}
Object test;
try{
if(constructor.getParameterTypes().length == 0){
test = constructor.newInstance(new Object[0]);
if(test instanceof TestCase)
((TestCase)test).setName(name);
}else{
test = constructor.newInstance(new Object[]{name});
}
}catch(Exception e){
...(略)
}
return (Test)test;
}
}
2.2 运行阶段(运行所有TestXXX型的测试方法)
- 创建
TestResult实例; - 将
junit.textui.TestRunner的监听器fPrinter加入到result的监听器列表中(观察者模式); - 开始计时;
run(result)测试运行;- 结束计时;
- 结果输出;

参考资料:
- Junit3.8.1执行流程
- 基于Junit3.8和Junit4.x的单元测试详解
- 开源代码啃不动,不如先定个小目标
- 分析JUnit框架源代码
- JUnit 3.8.1 源码学习
- JUnit 3.8.1 源码分析
Junit 3.8.1 源码分析(一)的更多相关文章
- Junit 3.8.1 源码分析之两个接口
1. Junit源码文件说明 runner framework:整体框架; extensions:可以对程序进行扩展; textui:JUnit运行时的入口程序以及程序结果的呈现方式; awtui:J ...
- JUnit源码分析 - 扩展 - 自定义Rule
JUnit Rule简述 Rule是JUnit 4.7之后新加入的特性,有点类似于拦截器,可以在测试类或测试方法执行前后添加额外的处理,本质上是对@BeforeClass, @AfterClass, ...
- JUnit源码分析 - 扩展 - 自定义RunListener
RunListener简述 JUnit4中的RunListener类用来监听测试执行的各个阶段,由RunNotifier通知测试去运行.RunListener与RunNotifier之间的协作应用的是 ...
- spring源码分析(二)Aop
创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...
- 【JUnit4.10源码分析】5 Statement
假设要评选JUnit中最最重要的类型.或者说核心,无疑是org.junit.runners.model.Statement.Runner等类型看起来热闹而已. package org.junit.ru ...
- Robotium源码分析之Instrumentation进阶-attach
在分析Robotium的运行原理之前,我们有必要先搞清楚Instrumentation的一些相关知识点,因为Robotium就是基于Instrumentation而开发出来的一套自动化测试框架.鉴于之 ...
- Robotium源码分析之Instrumentation进阶
在分析Robotium的运行原理之前,我们有必要先搞清楚Instrumentation的一些相关知识点,因为Robotium就是基于Instrumentation而开发出来的一套自动化测试框架.鉴于之 ...
- Hadoop之HDFS原理及文件上传下载源码分析(上)
HDFS原理 首先说明下,hadoop的各种搭建方式不再介绍,相信各位玩hadoop的同学随便都能搭出来. 楼主的环境: 操作系统:Ubuntu 15.10 hadoop版本:2.7.3 HA:否(随 ...
- MyBatis源码分析之环境准备篇
前言 之前一段时间写了[Spring源码分析]系列的文章,感觉对Spring的原理及使用各方面都掌握了不少,趁热打铁,开始下一个系列的文章[MyBatis源码分析],在[MyBatis源码分析]文章的 ...
随机推荐
- Oracle:shared memory realm does not exist
1. 先描述一个连接Oracle 10g的错误:“shared memory realm does not exist” 如图所示Sqlplus连接时出现这个错误: 2. Oracle 服务器主要组件 ...
- Phoenix的数据类型和操作符、函数
其实官方文档已经有这些东西了,如下: http://phoenix.apache.org/language/functions.html http://phoenix.apache.org/langu ...
- 几种在Linux下查询外网IP的办法。
几种在Linux下查询外网IP的办法. Curl 纯文本格式输出: curl icanhazip.com curl ifconfig.me curl curlmyip.com curl ip.ap ...
- SQL Server 数据库同步,订阅、发布、复制、跨服务器
随便说两句 折腾了一周,也算把数据库同步弄好了.首先局域网内搭建好,进行各种测试,弄的时候各种问题,弄好以后感觉还是挺简单的.本地测试好了,又在服务器进行测试,主要的难点就是跨网段同步,最后也解决了, ...
- jackson 不拼null节点的注解
http://blog.sina.com.cn/s/blog_544a7be401011url.html ——————————————————————————————————————————————— ...
- java 包 和 物理目录 解惑
今天做 JUnit 实验, 发现在物理实际不同的目录(src, testsrc)下可以使用相同的包名, 并且在这两个目录下, 都有个子目录 coolUnit (这个子目录是配合 package 使用的 ...
- jquery checkbox勾选/取消
作者:@keenleung本文为作者原创,转载请注明出处:http://www.cnblogs.com/KeenLeung/p/3799895.html 目录 <form> 你爱好的运动是 ...
- 微信JS-SDK文档
微信JS SDK 调用详解 微信JS SDK 调用详解... 1 概述... 2 使用说明... 2 接口调用说明... 4 基础接口... 4 判断当前客户端版本是否支持指定JS接口... 5 ...
- python中paramiko的安装
windows下安装并使用Python的SSH模块(paramiko+pycrypto+ecdsa) 2014-01-20 14:59 2223人阅读 评论(0) 收藏 举报 python+opens ...
- Eclipse中如何clean项目以及clean的作用
http://blog.csdn.net/vipmao/article/details/51228171