写在前面:本文基于Junit3.8.1版本,因为这是我第一次进行源码学习,先从简单的源码开始学起

1. 示例代码

1.1 准备工作

  • 下载Junit3.8.1的JAR包
  • 需要下载junit-3.8.1-sources.jarjunit-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)测试运行;
  • 结束计时;
  • 结果输出;

参考资料:

Junit 3.8.1 源码分析(一)的更多相关文章

  1. Junit 3.8.1 源码分析之两个接口

    1. Junit源码文件说明 runner framework:整体框架; extensions:可以对程序进行扩展; textui:JUnit运行时的入口程序以及程序结果的呈现方式; awtui:J ...

  2. JUnit源码分析 - 扩展 - 自定义Rule

    JUnit Rule简述 Rule是JUnit 4.7之后新加入的特性,有点类似于拦截器,可以在测试类或测试方法执行前后添加额外的处理,本质上是对@BeforeClass, @AfterClass, ...

  3. JUnit源码分析 - 扩展 - 自定义RunListener

    RunListener简述 JUnit4中的RunListener类用来监听测试执行的各个阶段,由RunNotifier通知测试去运行.RunListener与RunNotifier之间的协作应用的是 ...

  4. spring源码分析(二)Aop

    创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...

  5. 【JUnit4.10源码分析】5 Statement

    假设要评选JUnit中最最重要的类型.或者说核心,无疑是org.junit.runners.model.Statement.Runner等类型看起来热闹而已. package org.junit.ru ...

  6. Robotium源码分析之Instrumentation进阶-attach

    在分析Robotium的运行原理之前,我们有必要先搞清楚Instrumentation的一些相关知识点,因为Robotium就是基于Instrumentation而开发出来的一套自动化测试框架.鉴于之 ...

  7. Robotium源码分析之Instrumentation进阶

    在分析Robotium的运行原理之前,我们有必要先搞清楚Instrumentation的一些相关知识点,因为Robotium就是基于Instrumentation而开发出来的一套自动化测试框架.鉴于之 ...

  8. Hadoop之HDFS原理及文件上传下载源码分析(上)

    HDFS原理 首先说明下,hadoop的各种搭建方式不再介绍,相信各位玩hadoop的同学随便都能搭出来. 楼主的环境: 操作系统:Ubuntu 15.10 hadoop版本:2.7.3 HA:否(随 ...

  9. MyBatis源码分析之环境准备篇

    前言 之前一段时间写了[Spring源码分析]系列的文章,感觉对Spring的原理及使用各方面都掌握了不少,趁热打铁,开始下一个系列的文章[MyBatis源码分析],在[MyBatis源码分析]文章的 ...

随机推荐

  1. malloc,我误解你了

    malloc用于动态申请内存,这个学过C语言的都知道.忘记了在哪本书上看到,malloc申请的内存不一定是连续,于是一直记住了.这句话有错吗?没有!但是当时只是记住了这个知识点,而没有深入的思考.直到 ...

  2. [fork]Linux中的fork函数详解

    ---------------------------------------------------------------------------------------------------- ...

  3. [爬虫]Python爬虫基础

    一.什么是爬虫,爬虫能做什么 爬虫,即网络爬虫,大家可以理解为在网络上爬行的一直蜘蛛,互联网就比作一张大网,而爬虫便是在这张网上爬来爬去的蜘蛛咯,如果它遇到资源,那么它就会抓取下来.比如它在抓取一个网 ...

  4. HDFS的实现机制

    参考以上这张图,实际上我们客户端访问HDFS里面的内容时,并不需要真实知道内容存在于服务器的内容的真实路径,我们只需要知道一个虚拟路径就可以,比如最上面的hdfs://weekend110:9000/ ...

  5. ansible之并行运行

    ansible之并发运行 转载 2016年07月14日 12:33:39 标签: 并发 / ansible 4474 ansible默认只会创建5个进程,所以一次任务只能同时控制5台机器执行.那如果你 ...

  6. PostgreSQL视频去重 图片去重系列1

    PostgreSQL 在视频.图片去重,图像搜索业务中的应用 图片搜索 PostgreSQL的图像搜索插件使用了非常主流的Haar wavelet技术对图像进行变换后存储 gist 索引方法(支持pa ...

  7. 【转】伪O2O已死?2016年实体零售将迎来真正的O2O

    O2O果真如所谓的经济学家许小年所说“是两边都是零,中间一个2货”吗?我觉得,经济学家不是说相声的,这种哗众取宠的观点不应该出自一个严谨的经济学家之口.而且,我也不认为许小年真正懂什么叫O2O. 但O ...

  8. Dirichlet Distribution

    Beta分布: 二项式分布(Binomial distribution): 多项式分布: Beta分布: Beta分布是二项式分布的共轭先验(conjugate prior) Dirichlet Di ...

  9. virtualbox pxe启动

    在设置——系统中更改启动顺序,优先使用网路启动,如果你的网络环境支持PXE启动,就可以使用网络安装了. 转自: http://blog.csdn.net/huanghuibai/article/det ...

  10. KVC/KVO之KVO

    本章将分为三个部分: KVO是什么 KVO有什么用 KVO例子 KVO是什么 KVO,即NSKeyValueObserving,一个非正式的Protocol,提供一种机制来间接观察其他对象属性的变化. ...