本文算是一个关于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. .net core 使用DES加密字符串

    找了很久,都是用的第三方的插件处理,但是第三方的插件不兼容.net core中内置包. 接下来分享自己的方法: 1.创建一个加密方法类:SecurityHelper. public class Sec ...

  2. 关于虚拟机VM

    装Vmware虚拟机+安装系统不再困难 不要再以为你是女生,你就可以不用学装系统,亲,我们是计算机系的女生,顶起!!呼啦呼啦,这篇我装VM+系统的记录,作为勉励. 想必很多人都会使用到虚拟机,因为我们 ...

  3. Unity3D中Prefab

    Prefab概念: Prefab是一种资源类型--存储在项目视图中的一种可反复使用的游戏对象.因而当游戏中须要非常多反复使用的对象.资源等时,Prefab就有了用武之地.它拥有下面特点: 能够放到多个 ...

  4. [TypeScript] Using Lodash in TypeScript with Typings and SystemJS

    One of the most confusing parts of getting started with TypeScript is figuring out how to use all th ...

  5. JAVA 上加密算法的实现用例---转载

    通常 , 使用的加密算法 比较简便高效 , 密钥简短,加解密速度快,破译极其困难.本文介绍了 MD5/SHA1,DSA,DESede/DES,Diffie-Hellman 的使用. 第 1 章基础知识 ...

  6. 【转】正确使用Block避免Cycle Retain和Crash

    原文地址:http://tanqisen.github.io/blog/2013/04/19/gcd-block-cycle-retain/ 使用指南:http://blog.csdn.net/nic ...

  7. Motion——shake攻略

    1.子类化窗口 如果响应链中没有motionEnded:withEvent:消息的接收者,那么该消息就会被发送给应用程序的window对象.所以需要在window对象上拦截motionEnded:wi ...

  8. Google Map API v2 (三)----- 地图上添加标记(Marker),标记info窗口,即指定经纬度获取地址字符串

    接上篇 http://www.cnblogs.com/inkheart0124/p/3536322.html 1,在地图上打个标记 private MarkerOptions mMarkOption; ...

  9. ionic 项目分享No.2——简化版【转】

    写在文章前:由于最近研究ionic框架,深感这块的Demo寥寥可数,而大家又都藏私,堂堂天朝,何时才有百家争鸣之象,开源精神吾辈当仁不让!                                ...

  10. 鼠标移入 移出div div会消失的处理

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...