本文算是一个关于Junit4相关的知识分享,但是不同于网上大段的源码分析,模式学习文章,我想通过问答的形式,引出代码来简明阐述JUnit4是如何实现需要的功能的。

考虑到任何一个框架,都是为了解决问题而存在的。那么我想,带着问题去看源码会不会事半功倍呢?

Note:本文基于Junit4.11源码

Junit4怎么就能跑Case?

众所周知,JUnit框架能帮助跑单元测试的Case,那么它到底是如何实现的呢?换句话说,如果没有JUnit,我们会怎么执行Case?

OK,很简单,一个case就是一个方法,那要想执行他们,直接在Main方法里调用就可以了。

但是当Case很多时,我们就得一个一个在Main方法里显示的调用Case。

虽然稍显繁琐,还是可以解决问题的,不过拓展性就不敢恭维了,别人也没办法使用我们已写的东西?!

那么,如果要上升到框架层面,能够让更多的人使用,该怎么做呢? Junit给了我们很好的例子.

好的单元测试框架一定是最大限度的方便使用者,让其尽可能只关注单元测试本身,而不是其他一些冗余的事情.

很明显Junit做到了这一点, 它不需要你去显示的自己调用Case,一切都帮你做好,你只要告诉它要测哪个类就好了,以JUnit4.11默认的Runner为例:

BlockJUnit4ClassRunner aRunner = new BlockJUnit4ClassRunner(JunitTest.class);
aRunner.run(new RunNotifier());

Debug进去,我们就会发现,原来JUnit是用反射机制来跑我们写的Case。

public class InvokeMethod extends Statement {
private final FrameworkMethod fTestMethod;
private Object fTarget; public InvokeMethod(FrameworkMethod testMethod, Object target) {
fTestMethod = testMethod;
fTarget = target;
} @Override
public void evaluate() throws Throwable {
fTestMethod.invokeExplosively(fTarget);
}
}

这里的InvokeMethod就是实际执行方法的类,跟进去方法:fTestMethod.invokeExplosively(fTarget);

我们就会看到Method.invoke(obj,args)的最终反射调用。

    public Object invokeExplosively(final Object target, final Object... params)
throws Throwable {
return new ReflectiveCallable() {
@Override
protected Object runReflectiveCall() throws Throwable {
return fMethod.invoke(target, params);
}
}.run();
}

如何实现 @Test 标记功能?

Junit在4.0以后进行了一个大的版本变动,引入了Java 1.5的注解功能,就像我们常用的 @Test, @BeforeClass, @AfterClass 一样,那么这些功能是如何实现的呢?

以 @Test 为例:

 @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Test {
static class None extends Throwable {
private static final long serialVersionUID = 1L; private None() {
}
}
Class<? extends Throwable> expected() default None.class;
long timeout() default 0L;
}

它以RetentionPolicy.RUNTIME标记, 就表示这个注解在运行时仍然会被JVM保存,因此就可以通过反射得到它:

protected List<FrameworkMethod> computeTestMethods() {
return getTestClass().getAnnotatedMethods(Test.class);
}

这样JUnit就得到了所有你要跑的Case。

而对于 @BeforeClass, @AfterClass 都是一个原理。

Junit4如何判断结果?

上面说到如何找Case,如何跑Case,那么对于一个完成的执行流程,我们还缺一块:你的Case是Pass还是Fail?

比如下面:

org.junit.Assert.assertTrue("check assert method", false);

我们通常是用Assert去做断言的,还有其他的方法,比如assertEqulas,assertNotEqulas。显而易见,上面的断言结果一定是Fail的,那具体是如何实现的呢?

要解开谜题,我们先看看Assert.assertTrue(String message, boolean condition)方法的具体实现:

static public void assertTrue(String message, boolean condition) {
if (!condition) {
fail(message);
}
} static public void fail(String message) {
if (message == null) {
throw new AssertionError();
}
throw new AssertionError(message);
}

当condition是false时,它会抛一个java.lang.AssertionError异常。这个类是从Java 1.4引入的,并且它跟所有的Java的异常一样都是从Throwable继承来的。

那Junit如何捕获呢?

org.junit.runners.ParentRunner<T>类我们找到了答案:

protected final void runLeaf(Statement statement, Description description,
RunNotifier notifier) {
EachTestNotifier eachNotifier = new EachTestNotifier(notifier, description);
eachNotifier.fireTestStarted();
try {
statement.evaluate();
} catch (AssumptionViolatedException e) {
eachNotifier.addFailedAssumption(e);
} catch (Throwable e) {
eachNotifier.addFailure(e);
} finally {
eachNotifier.fireTestFinished();
}
}

这个方法目的就是执行单个Case,它是用Try Catch来捕获所有非预期的异常错误。

只要Catch到Throwable异常了,很明显Case就挂了。反之,Case则是pass的。

这里还可以继续深入,比如我们知道,@Test 有一个expected参数,可以让我们填入期望捕获的异常,那么JUnit如何实现的呢?

总结

好了,我们来看看我们都说了啥:

  • Junit通过 @Test 注解,找到我们想跑的Case
  • 通过反射,来执行我们的Case
  • 最后通过Catch Throwable exception来判断我们的case 是Pass还是Fail

很明显JUnit还有很多其他的功能,比如TestSuite,Rule,各种Runners,这里不在一一罗列了。

我想,作为表达一条Case执行的主线,讲到这里应该已经足够了,不是嘛?

如果您看了本篇博客,觉得对您有所收获,请点击下面的 [推荐]

如果您想转载本博客,请注明出处大卡的博客[http://www.cnblogs.com/jinsdu/]

如果您对本文有意见或者建议,欢迎留言

简单易懂, JUnit 框架问答的更多相关文章

  1. 一个简单的JUnit项目

    本人一直很喜欢JAVA,可是真正接触到JUnit也不过半年.由于公司进行网页测试,采用的是 JUnit+selenium的方式搭建的测试框架,然后采用JAVA语言编写,所以本人也好好研究了一下JUni ...

  2. 最简单的Java框架

    框架framework的目的是定义骨架式方案,处理各种相同的底层细节:而开发人员使用框架时,能够依照自己的需求实现自己的功能--仅仅须要填入自己的东西/flesh. 最简单的框架,类似于JUnit,它 ...

  3. java自动化-junit框架简述

    本人使用的是java的junit框架来组织的自动化测试,故我这边需要简单介绍一下junit框架 首先,建议自行百度一下junit框架,先有一个大概的了解 所谓的接口自动化测试,会对多个接口中每一个接口 ...

  4. 简单理解laravel框架中的服务容器,服务提供者以及怎样调用服务

      laravel被称为最优雅的框架,最近正在学习中,对于用惯了thinkphp.ci框架的人来说,服务容器.服务提供者,依赖注入这些概念简直是一脸懵逼.我花了些时间梳理了一下,也不敢确定自己说的是对 ...

  5. 通过Maven简单搭建SSM框架

    创建Maven就不用多说了,下面直接看Pom.xml里面的依赖吧 <properties> <!-- spring版本号 --> <spring.version>5 ...

  6. 分析 JUnit 框架源代码

    本文转载至http://www.ibm.com/developerworks/cn/java/j-lo-junit-src/ 分析 JUnit 框架源代码 理解 JUnit 测试框架实现原理和设计模式 ...

  7. 用Python写一个简单的Web框架

    一.概述 二.从demo_app开始 三.WSGI中的application 四.区分URL 五.重构 1.正则匹配URL 2.DRY 3.抽象出框架 六.参考 一.概述 在Python中,WSGI( ...

  8. PHP之简单实现MVC框架

    PHP之简单实现MVC框架   1.概述 MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种 ...

  9. Spring整合JUnit框架进行单元测试代码使用详解

    一.Spring提供的JUnit框架扩展:   1. AbstractSpringContextTests:spring中使用spring上下文测试的Junit扩展类,我们一般不会使用这个类来进行单元 ...

随机推荐

  1. 安装MYSQL 出现Error 1045 access denied 的解决方法

    操作系统:WINDOWS10 系统 数据库版本:mysql 5.x 提示:access denied for user 'root'@'localhost' using password yes/no ...

  2. jQuery练习实例(四)

    最近写的jquery实例--jQuery图片九宫格样式鼠标悬停图片滑动切换效果 有兴趣的同学可以参考一下,这幅效果,个人觉得挺不错的 <%@ page language="java&q ...

  3. java中使用队列:java.util.Queue

    在java5中新添加了java.util.Queue接口,用以支持队列的常见操作.该接口扩展了java.util.Collection接口.Queue使用时要尽量避免Collection的add()和 ...

  4. JAVA 强引用、软引用、弱引用、虚引用

    http://www.cnblogs.com/absfree/p/5555687.html

  5. (转载)关于ArrayList的5道面试题

    我以面试官的身份参加过很多Java的面试,以下是五个比较有技巧的问题,我发现有些初级到中级的Java研发人员在这些问题上没有完全弄明白,似懂非懂.所以我写了一篇相关的文章,帮助初级Java研发人员弄清 ...

  6. XC应用系列作品(Android应用)

    XC系列应用,如真题园手机客户端1.1等应用已经分别在 360手机助手.腾讯应用宝.百度手机助手.小米应用商店.豌豆荚.应用汇.木蚂蚁等安卓市场平台上线了! 本页面的系列应用是本人的开发的一Andro ...

  7. iOS UIKit:CollectionView之设计 (1)

    collection view(UICollectionView对象)使用灵活和可扩展的布局来描述有序的数据项,其一般情况下以网格的形式来展示内容,但并非一定如此. 1 基础 为了将数据展示在屏幕中, ...

  8. RedHat7配置Nginx实现多域名虚拟主机的SSL/TLS认证(实现单IP以不同证书服务于不同域名)

    以RedHat7(64bit)平台为例 如果RedHat源没法用,可以使用EPEL源 # rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-rel ...

  9. HttpWebRequest结合HtmlAgilityPack实现网页form提交

    年前一个项目,需要在某个系统实现系统自动操作. 系统页面使用form提交,页面参数较多,也参数设计一系列计算逻辑,改动一个值,其他值自动改变. 传统方法使用正则表达式匹配参数,构建post参数进行请求 ...

  10. WEB 中的一些名词解释

    OOP: 面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构. AOP: AOP为Aspect Oriented Programmin ...