`
zhongxiucheng
  • 浏览: 70898 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论
阅读更多

作为一个底层编码人员来说,编写一个足够简单的方法,通常并不会想到测试。我这里所说的“足够简单”并不是指业务逻辑,而是指程序自身的结构,它没有复杂的条件判断,不涉及太多的变量,也没有复杂的递归与繁琐的数据结构,程序调用这样的方法一般不会有太多的变数。但是一般象这样的方法在程序中一般是比较少的,所以很多方法都是需要测试一下,但是为了方便或者赶时间(有时候也是为了偷懒),只是在程序逻辑不正确或者程序报异常才会想到去测试下可能出现问题的方法。而测试最常见的方法一般就是用一个单独main方法来运行想要测试的方法,然后看输出情况;对于一个J2EE程序来说,很多方法是不可以用或者很难用main方法执行以进行测试,大多数时候是根据一次有效的请求与响应使待测试的方法得以运行,然后根据控制台输出信息来找出程序的缺陷。如果逻辑比较复杂的时候可以借助调试工具来发现问题。

上面谈到的少量测试,当然也是一种测试,但是它很难规模化(一次就运行一个用例),也很难自动化(要通过人去判断),用例都是临时性的无法重复利用。JUnit是什么东西呢?我个人认为就是把这样一些零散的测试有机组织在一起的一个框架,使前面所说的那些小打小闹上升到一个更高的层次,测试用例可以重复使用,测试可以自动化执行,当然还有其它一些好处。

左图是JUnit框架的核心构架:上面的TestTestCaseTestSuit是一个组合模式;而下面的TestResultBaseTestRunnerTestListener是一个观察者模式。TestCase继承Assert类,实现Test接口,同时它依赖TestResult类,这个依赖实际是Test接口所规定的,当运行一个TestCase时需要一个TestResult实例;TestSuit类实现了Test接口,它表现为TestCase的聚集,而实际是Test的聚集,TestSuiteBaseTestRunner运行的实体, 但最终TestSuite还是委托TestCase来完成实际的运行;TestResult也是一个很重要的类,它主要用于收集测试的结果,并向所有注册的TestListerner监听器广播测试的及时情况,所有TestRunner都是一个监听器,所以它不仅可以从TestResult获取测试的最终情况,公平可以知道测试的即时情况。TestCaseTestSuitTestResult这三个类在测试运行时它们是最活跃,最核心的类。整个测试运行一个大致过程是这样的:首先由一个TestRunner启动运行,TestRunner必须获取一个运行的对象,这个对象就是TestSuite(关于TestSuite怎样建立与获取后文详细介绍);获取TestSuite以后TestRunner就会委托它运行它的run方法,这个方法是一个公有方法即:public void run(TestResult result) 这个方法的参数是一个TestResult对象,也是由TestRunner产生的,用来收集测试结果的;它是一个很重要的参数,在产生这个TestResult对象之后TestRunner会做一件很重要的事情,那就是向这个产生的TestResult对象注册自己,以便监听测试运行的情况;TestRunner委托TestSuite对象运行时,TestSuite对象就会对自己保留的多个Test对象(可能是TestCase也可能是TestSuite)进行循环递归遍历,当对象是TestSuite是就递归(实际也是执行它的run方法),当对象是TestCase时就委托这个TestCase对象来执行它的run方法这个方法实际也是public void run(TestResult result)这个方法是Test接口所规定的一个方法,如此层层递归就会将运行委托给包含在TestSuite对象中的每一个TestCase对象,上面说TestTestCaseTestSuit构成一个组合模式的精髓也在于此,它们的关系就象文件与文件夹的关系;当运行委托给一个具体的TestCase对象后,此TestCase对象会从run方法参数获取最初传入的TestResult对象,此时的TestCase对象并不执行自己名称所标识的测试方法,而是将运行进一步委托给传入的TestResult对象,并且将自己作为参数传递给TestResult对象的run方法,此方法的签名为:protected void run(final TestCase test)之所以这么做主要是为了让TestResult对象容易收集测试结果;TestResult对象获取运行控件权之后,TestResult对象首先就会通知各监听器,一个测试(指对一个方法的测试)开始了,因为TestResult对象在获取运行控件权时获取了一个TestCase对象,这个对象就是此次测试所要测试的对象(说的更具体一点,是要运行这个TestCase对象中的一个方法,具体是哪个方法要依赖构造TestCase对象时设置的唯一名称标识,实际是方法名),因此,在通知各监听器之后,TestResult对象就是会执行TestCase对象的runBare方法,来执行实际的测试runBare方法没有任何参数,runBare方法首先执行资源管理方法setUp(),这是任何一个测试都会执行的一个环境预设方法,紧接着就会执行待测试的方法(这个方法是通过反射取得,它的外层用一个方法包装,方法签名为:protected void runTest() throws Throwable),执行所有测试方法实际都是执行这个方法,执行完成之后,再执行资源管理方法tearDown()方法以释放资源,这就是runBare方法执行的全过程;runBare方法执行完后,TestResult对象就会收集测试结果,即执行addFailureaddError方法,之后就会通知各监听器,此次测试已经完成,即执行endTest方法,至此宣告一次测试完成,如果最初获取的TestSuite还“含有”其它TestCase对象,那测试就会从第步开始进入下一轮,否则就会终止测试。

下图是对这一执行过程的时序描述

时序图上面对JUnit的核心构架及运行情况进行了粗略的分析,下面就在实际使用中可能出现的问题,以及一些常见的疑问汇集如下:

A. TestRunner如何获取TestSuite

TestRunner在启动时候一般都会要求传递一个参数,这个参数最常见的一种就是一个继承于TestCase类的类名,至于TestRunner究竟可以跟什么样的参数没有研究过,但根据我所知的情况至少有两种情况,一个就是继承于TestCase类的类名,另一个就是跟TestSuite类名。这里要特别说明的一点TestSuite类并不是一个继承于TestSuite的类而是具有一个特定方法签名的类,这个特定的方法签名为:public static Test suite();这样的方法被称之为Test Suite至少Eclipse上是这样的,Eclipse说新建一个Test Suite就是新建一个具有此方法签名的类,这确实很难让人理解,把方法的签名都写死了。

这个方法为什么如此重要呢?因为TestRunner要靠这个方法来提供一个Test(大多数情况是一个TestSuite而不是一个TestCase)它被看这一组测试的根。一个典型的Test Suite如下:

package qw.zxc.junit;

import junit.framework.Test;

import junit.framework.TestSuite;

/**

* @author Administrator

* 主要是为了验证一个TestSuite的建立,体会何为"建立一个TestSuite"

*/

public class AllTests {

public static Test suite() {

TestSuite suite = new TestSuite("测试一个TestCase自带suite方法的情况");

//$JUnit-BEGIN$

suite.addTest(TestCalculate.suite());

suite.addTestSuite(TestCalculate2.class);

//$JUnit-END$

return suite;

}

}

一个TestCase中就也可以有这样一个方法,这个方法就是告诉TestRunner要运行哪些测试方法,但是TestCase中并不一定要有这个方法,那么如果把一个TestCase传给TestRunner,并且这个类不含有这个方法,TestRunner是如何得知要运行哪些测试方法呢?原因是这样的,TestRunner接收 一个TestCase类名参数时,并且这个类没有方法签名public static Test suite();TestRunner会利用反射将所有以test开头的方法集中起来放入一个TestSuite类对象中,以此对象作为返回对象以待运行其中的测试方法如果TestRunner接收 一个TestCase类名参数时,但含有方法public static Test suite();TestRunner就不会利用反射,而是直接调用此方法,来获取一个Test对象以运行其中的测试方法如果TestRunner接收 一个含有方法签名:public static Test suite();的类名时(它不一TestCase也不一定是TestSuite),它也会直接调用此方法来获取一个Test对象以运行其中的测试方法。

B. 如何自己构建一个有效TestSuite

通过上面的分析可知,不管是上面的哪一情况,最终TestRunner都会想尽办法从给定的参数获取一个TestSuite类对象(标准说法应该是Test对象,但是绝大多数情况下是TestSuite对象,而不会是一个TestCase对象),那么如何构建一个有效TestSuite类对象呢?主要可以从以下几个方法签名入手去考虑:

public TestSuite();

public TestSuite(String name);

public TestSuite(final Class theClass);

public TestSuite(Class theClass, String name);

public void addTest(Test test);

public void addTestSuite(Class testClass);

public TestCase();

public TestCase(String name);

这里总共有八个方法前六个属于TestSuite,后两个属于TestCase,下面对上面八个方法作一个详细的说明:

* 第一个方法:public TestSuite();是构造一个空的TestSuite其中不包括任何待运行方法;

* 第二个方法:public TestSuite(String name);实际与第一个方法类似,它只是为这一组集中在一起测试命了一个名字,一般这个名字应该与这组测试功能相关的有意义的名字;

* 第三个方法:public TestSuite(final Class theClass);这个方法比较重要,这里的参数是一个Class类型,但它必须是一个TestCase型,此方法作用就是通过反射来构造一个TestSuite类对象,其中已经包含了给定的TestCase类的所有以test开头的方法,注意这里不管这个TestCase是否具有方法签名:public static Test suite();一律使用反射而不会使用“有则调用;无则反射”的规则。

* 第四个方法:public TestSuite(Class theClass, String name); 实际与第三个方法一样,只是多了一个给这组测试起一个自己喜欢的名字。

* 第五个方法:public void addTest(Test test);这是一个比较灵活的方法,它表示向一个TestSuite中添加要运行的方法,这里的参数是Test所以它既可以是一个TestSuite,与可以是一个TestCase,但是这里如果是TestCase千万要小心,可以先看一下第七与第八个方法,这两个方法是构造一个TestCase,我们说构造一个TestCase并不难,但是构构造一个添加到TestSuite中能够正常执行的TestCase并不是随便new一下就可以了,也不是一个随便的名字就可以的,我们说在TestSuite中的测试方法运行依赖的是反射,要知道运行的是TestCase中的哪一个测试方法是用的TestCasename标识的,所以在构造TestCase时必须给出正确的name标识,这个标识必须是你想运行的那个测试方法的名字。这好象是添加单个方法的唯一方法。

* 第六个方法:与第三个方法相关,它实际是利用第三个先构造一个TestSuite然后再调用第五个方法将构造TestSuite添加到当前的TestSuite

分享到:
评论

相关推荐

    SpringMvc单元测试Junit

    SpringMvc单元测试Junit是Java开发中的重要实践,主要用于确保应用程序的特定部分,如控制器,服务或DAO,按预期工作。在这个Demo中,我们将深入探讨SpringMvc如何与JUnit结合进行有效的单元测试,以及如何利用这些...

    单元测试Junit 参考PPT

    【单元测试Junit 参考PPT】是一个详细介绍Java项目中单元测试的教育资源,主要针对Junit这个单元测试框架进行讲解。单元测试是软件开发过程中的一个重要环节,它旨在验证软件中的最小可测试单元,如单个方法或类,...

    单元测试JUnit常用断言方法

    ### 单元测试JUnit常用断言方法 #### JUnit简介 JUnit是一款用于Java语言的单元测试框架,由Kent Beck与Erich Gamma共同开发维护。它主要用于编写和运行可重复的测试案例,帮助开发者确保代码质量并及时发现潜在...

    JAVA单元测试JUnit

    ### JAVA单元测试JUnit的核心知识点详解 #### 一、JUnit概览与重要性 JUnit作为一款卓越的Java单元测试框架,自问世以来便以其强大的功能和易用性深受开发者喜爱。由软件大师Erich Gamma和Kent Beck共同打造,...

    Java单元测试JUnit4.7

    JUnit是Java领域最广泛使用的单元测试框架,它为开发者提供了一种简洁、高效的测试工具。JUnit 4.7是该框架的一个版本,包含了对之前版本的改进和新功能。 在Java开发中,单元测试是对单个或小部分代码进行的功能...

    单元测试junit-jar包

    在这个“单元测试junit-jar包”中,我们关注的是如何使用Junit进行单元测试。 Junit是一个开源项目,由Eclipse基金会维护,它提供了丰富的断言方法,用于比较预期结果和实际结果,以及注解(Annotations)来标记...

    单元测试JUnit学习专题

    ### 单元测试JUnit学习专题知识点详述 #### 一、单元测试概述 **单元测试定义**:单元测试是软件开发中的一个测试方法,通常针对软件中的最小可测试单元进行验证,例如一个类或者一个函数。其目的是确保每个单元...

    单元测试JUnit4和DbUnit

    为了更好地学习和实践这些概念,文档"单元测试JUnit4和DbUnit.doc"可能包含了详细的步骤和示例代码,而"dbunitAndJunit4"和"junit4"这两个文件夹可能包含了相关的练习项目或者源码,通过阅读和运行这些代码,可以...

    软件测试 单元测试 junit

    软件测试 单元测试 junit 开源工具哦,希望大家喜欢用!

    Java 单元测试 JUnit 5 快速上手 示例项目

    Java 单元测试 JUnit 5 快速上手 示例项目Java 单元测试 JUnit 5 快速上手 示例项目Java 单元测试 JUnit 5 快速上手 示例项目Java 单元测试 JUnit 5 快速上手 示例项目Java 单元测试 JUnit 5 快速上手 示例项目

    单元测试Junit 4.7

    【单元测试Junit 4.7】 单元测试是软件开发中的一个重要环节,它允许开发者针对程序的各个独立组件进行验证,确保每个单元的功能正确性。JUnit是Java编程语言中最广泛使用的单元测试框架,而Junit 4.7是其一个重要...

    单元测试junit

    ### 单元测试junit:理解与实践 在软件开发领域,单元测试是确保代码质量、功能正确性和可维护性的关键环节。JUnit作为Java领域最流行的单元测试框架之一,为开发者提供了一套全面且易用的工具,帮助他们编写高质量...

    用Junit进行单元测试junit4.5

    在Java世界中,**JUnit**是最广泛使用的单元测试框架。本篇将重点介绍如何利用**JUnit 4.5**进行单元测试,以及这个版本的一些特性。 ### JUnit简介 JUnit是一个开源的、基于Java的测试框架,由Ernst Leiss和Kent ...

    junit单元测试jar包集

    这里提到的四个文件是Java开发中常用的单元测试框架和库,分别是JUnit、DBUnit、Unitils和Mockito。让我们逐一深入探讨它们的功能和使用方法。 **JUnit** 是Java领域中最广泛使用的单元测试框架,这里的`junit-4.11...

    java.单元测试JUnit(解决方案).md

    java.单元测试JUnit(解决方案)

    java.单元测试JUnit(处理方案示例).md

    java.单元测试JUnit(处理方案示例).md

    hamcrest-core-1.3.jar 单元测试JUnit框架必须jar包

    hamcrest-core-1.3.rc2.jar 单元测试JUnit框架必须引用的jar包,免费分享给大家

Global site tag (gtag.js) - Google Analytics