JUnit 是JAVA语言事实上的标准测试库。JUnit 4是三年以来最具里程碑意义的一次发布。它的新特性主要是针对JAVA5中的标记(annotation)来简化测试,而不是利用子类、反射或命名机制。本文将讲述如何使用JUnit 4,当前前提是你最好具有JUnit的使用经验.
JUnit, 由Kent Beck 和 Erich Gamma开发,几乎是JAVA开发最重要的第三方工具。正如Martin Fowler 所说,“在软件开发领域,从来就没有如此少的代码起到了如此重要的作用“。由于JUnit,JAVA代码变得更健壮,更可靠,BUG也比以前更少。由于JUnit (由Smalltalk's的SUnit得来) 的出现,随后产生了许多xUnit的测试工具,如nUnit (.NET), pyUnit (Python), CppUnit (C++), dUnit (Delphi) 和其它不同平台及语言的测试相关的工具。
虽然JUnit也只是一个工具,但其产生的思想和技术却较其架构更意义重大。单元测试,测试先行的编程方式,测试驱动的开发方式,并非必须由JUNIT实现,也不一定要用SWing实现GUI界面。JUNIT最近的一次更新是在三年前,但它比其它大多数有BUG的框架都要健壮,更重要的是,JAVA一直在改进。现在JAVA支持泛型,枚举,可变长度参数,以及标记语言(开创了开发可重用框架的新局面)。
JUnit's的停滞不前使得那些想要变革的开发人员换其它测试工具.挑战者有Bill Venners的Artima SuiteRunner和Cedric Beust的TestNG.这些工具库虽然有值得推荐的功能,但没有任何一款的地位能与JUNIT相比,没有任何一款工具被其它业界产品如Ant, Maven, Eclipse广泛支持.因此Beck 和Gamma双开始利用JAVA5的新特性来开发新版的JUNIT,目的是利用JAVA5中的标记特性使得单元测试开发更容易。Beck说:“JUNIT4的主要目的是通过简化JUNIT的使用鼓励更多的开发人员写更多的测试”。虽然会与以前的版本兼容,但JUNIT4与从JUNIT1.0就开始的版本相比会有一个非常大的变化.
注意: 修改基本框架是一把双刃剑,虽然JUNIT4的目的是清晰的,但细节仍有许多不同,因此本文只是一个简单的介绍,并不是最终文档.
测试方法
以前所有版本的JUNIT都使用命名机制和反射来定位测试,下面的代码测试1+1= 2:
import junit.framework.TestCase; public class AdditionTest extends TestCase { private int x = 1; private int y = 1; public void testAddition() { int z = x + y; assertEquals(2, z); } } |
而在JUNIT 4中,测试方法由 @Test 标记说明,如下:
import org.junit.Test; import junit.framework.TestCase; public class AdditionTest extends TestCase { private int x = 1; private int y = 1; @Test public void testAddition() { int z = x + y; assertEquals(2, z); } } |
使用标记的好处是你不用将所有测试方法命名为 testFoo() , testBar()等等以"test"开头的方法,下面的方法也同样可以工作: import org.junit.Test; import junit.framework.TestCase; public class AdditionTest extends TestCase { private int x = 1; private int y = 1; @Test public void additionTest() { int z = x + y; assertEquals(2, z); } } |
下面的代码也同样正确:
import org.junit.Test; import junit.framework.TestCase; public class AdditionTest extends TestCase { private int x = 1; private int y = 1; @Test public void addition() { int z = x + y; assertEquals(2, z); } } |
这种命名机制最大的优点是更适合你的待测试类或方法名称,例如,你可以使用ListTEst.contains()测试 List.contains() ;使用ListTest.addAll()测试 List.add()等等.
TestCase 还可以继续使用,但你没有必须再扩展为子类,只要你声明了@Test,你可以将测试方法放在任何类中,当然如要访问assert等方法,你必须要引用junit.Assert类,如下:
import org.junit.Assert; public class AdditionTest { private int x = 1; private int y = 1; @Test public void addition() { int z = x + y; Assert.assertEquals(2, z); } } |
你也可以使用JDK5中的新特性(static import)使得跟以前版本一样简单:
import static org.junit.Assert.assertEquals; public class AdditionTest { private int x = 1; private int y = 1; @Test public void addition() { int z = x + y; assertEquals(2, z); } } |
这种方法测试受保护的方法非常容易,因为你可以在测试类中继承有受保护方法的类.
SetUp 和TearDown
JUnit 3 中 test runners 会在每个测试之前自动调用 setUp()方法。此方法主要用于初始化变量,打开日志,重置环境变量等。下面是XOM's XSLTransformTest中的 setUp()方法:
protected void setUp() { System.setErr(new PrintStream(new ByteArrayOutputStream())); inputDir = new File("data"); inputDir = new File(inputDir, "xslt"); inputDir = new File(inputDir, "input"); } |
在JUnit 4中,你仍然可以在每个测试前初始化变量和配置环境,,然而,这些操作可以不用在Setup()中完成,你可以在初始化方法前面添加 @Beforer 来表示,如下:
@Before protected void initialize() { System.setErr(new PrintStream(new ByteArrayOutputStream())); inputDir = new File("data"); inputDir = new File(inputDir, "xslt"); inputDir = new File(inputDir, "input"); } |
你也可以有多个方法标记有@Before,所有方法都会在每个测试之前执行:
@Before protected void findTestDataDirectory() { inputDir = new File("data"); inputDir = new File(inputDir, "xslt"); inputDir = new File(inputDir, "input"); } @Before protected void redirectStderr() { System.setErr(new PrintStream(new ByteArrayOutputStream())); } |
清除环境与JUNIT3 差不多,在JUNIT3中使用 tearDown()方法,下面的代码是结束测试时回收内存:
protected void tearDown() { doc = null; System.gc(); } |
在JUnit 4中,你还可以使用 @After 标记来说明:
@After protected void disposeDocument() { doc = null; System.gc(); } |
与 @Before一样,你也可以有多个标记有 @After的清除方法,每个都会在执行完每个测试后执行。
最后,你不需要在父类中明确调用这些初始化或清除方法.test runner会自动调用这些标记的方法.子类中的@Before方法在父类的@Before方法之后执行(这与构造函数的执行顺序一样),而@After方法刚好相反,子类中的@After方法先执行.然而,多个@Before和@After方法的执行顺序就是未知的.
测试集范围的初始化
JUnit 4中引入了一项JUNIT3没有的新特性,类级别的setUp()和tearDown(),即在一个类的所有测试前执行初始化,并在所有测试完成后执行清除。
例如,一个测试类中的每个测试都要用到一个数据库连接或网络连接,或其它很耗资源初始化或释放的资源,用不着在每个测试方法前后进行操作,而只需要在测试类开始前后执行即可。下面的示例是使用第三方的库进行错误,在执行所有测试前将错误先重定向到非标准输出,然后在所有测试结束后再输出到需要的地方,这样就不会影响到测试过程中产生的其它信息。
// This class tests a lot of error conditions, which // Xalan annoyingly logs to System.err. This hides System.err // before each test and restores it after each test. private PrintStream systemErr; @BeforeClass protected void redirectStderr() { systemErr = System.err; // Hold on to the original value System.setErr(new PrintStream(new ByteArrayOutputStream())); } @AfterClass protected void tearDown() { // restore the original value System.setErr(systemErr); } |
上面的操作没有必须在每个测试前后执行。然而要注意的是,这种方法可能影响测试间的结果,如果一个测试改变了初始化的对象,而这个对象可能是其它测试的输入,那么测试的结果可能不正确,这种方法将依赖测试的顺序并可能引入BUG。当优化测试性能,并且当你改进了配置和基准测试后而仍然很慢时,如数据库连接或网络问题,你才需要考虑使用这种方法。只有这样,你才能每天执行多次测试。
异常测试
异常测试是JUNIT4中的最大的改进,以前异常测试是通过try catch实现,当抛出异常时,在try的最后添加一条fail()语句实现.如下:
public void testDivisionByZero() { try { int n = 2 / 0; fail("Divided by zero!"); } catch (ArithmeticException success) { assertNotNull(success.getMessage()); } } |
这种方法不仅难看,而且造成无论成功或失败,代码覆盖工具都不能执行某些代码.而在JUnit 4中,你可以在要抛出异常的代码中添加标记来声明一个异常是期望的:
@Test(expected=ArithmeticException.class) public void divideByZero() { int n = 2 / 0; } |
如果没有异常抛出,上面的测试则会失败,如果你想知道异常的详细信息或其它情况,你还是要使用try catch才行
需要忽略的测试
也许你有些测试需要很长时间才能执行完成,并非是这个测试应该跑得快,而是它做的很复杂和很慢的工作造成的.如访问远程网络错误,需要很久才能有反馈.如果你不想让这种测试破坏你整个测试过程,你可能想跳过这个测试.当然也有可能某个测试超出控制范围而失败.如W3C XInclude测试集中自动识别一些JAVA不支持的Unicode代码.为了防止这些测试总是通不过,可以使用标记 @Ignore 跳过这些测,如下:
// Java doesn't yet support the UTF-32BE and UTF32LE encodings @Ignore public void testUTF32BE() throws ParsingException, IOException, XIncludeException { File input = new File( "data/xinclude/input/UTF32BE.xml" ); Document doc = builder.build(input); Document result = XIncluder.resolve(doc); Document expectedResult = builder.build( new File(outputDir, "UTF32BE.xml") ); assertEquals(expectedResult, result); } |
test runner不会执行这些测试,但会说明这些测试被跳过了。在命令行测试界面中,字母“I”会表示测试跳过,或“E”表示测试失败,而不是用点”."表示成功.
$ java -classpath .:junit.jar org.junit.runner.JUnitCore nu.xom.tests.XIncludeTest JUnit version 4.0rc1 .....I.. Time: 1.149 OK (7 tests) |
要注意的是,假设这些测试由于某种理由放在最开始,如果你以后一直忽略这些测试,那些需要被测试的代码可能有问题而不会被检测到。因此忽略测试只是一个临时解决方法,并不是一个解决任何问题的真正办法。
时间测试
性能测试是单元测试中最头疼的问题,JUnit 4也未完全解决此问题, 你可以在JUNIT4的测试方法中添加一个时间参数。如果测试时间超过参数,则测试失败。如下,如果测试时间超过0.5秒,则此测试失败:
@Test(timeout=500) public void retrieveAllElementsInDocument() { doc.query("//*"); } |
除基准性能测试外,时间测试在网络测试方面也很有用.如果一个远端的主机或数据当掉或太慢,你可以跳过此测试而不用阻塞在这里,好的测试集可以在作了一些改动后很快的一遍一遍的执行,可能一天数十次.设置一个超时让测试更快的执行,下面的示例中如果分析http://www.ibiblio.org/xml 的时间超过2秒,则测试失败.
@Test(timeout=2000) public void remoteBaseRelativeResolutionWithDirectory() throws IOException, ParsingException { builder.build("http://www.ibiblio.org/xml"); } |
新的断言 JUnit 4 增加了两上断文方法用于比较数组:
public static void assertEquals(Object[] expected, Object[] actual) public static void assertEquals(String message, Object[] expected, Object[] actual) |
这两个方法采用最直接方法比较,如果数组长度相同,且每个对应的元素相同,则比较成功,否则不成功.参数为空的情况也作了考虑.
需要补充的地方
JUnit 4是一个非常基本的框架,还不是以前版本的升级。JUNIT3的开发人员会发现有些功能没有。
- 最大的特点就是没有GUI测试界面,当测试正确时是绿色条,而出错时红色的,你也可以在Eclipse中集成JUNIT使用,但JUNIT4既没有AWT也没有SWING的GUI测试界面;
- 另一个让人吃惊的是失败(期望错误)和错误(未预计的异常错误)没有明显区别,在JUNIT3中开发人员可以区分这两种情况,而在JUNIT4中不行;
- 最后一个特点是JUNIT中没有用于建立一堆测试类的 suite()方法,取而代之的是,采用变长参数传递未知数量的测试给test runner。
没有GUI测试界面的确不方便,但其它改变简化了JUNIT的使用,从当前JUNIT的操作手册和FAQ的数量就知道,而JUNIT4的文档将不会需要这么多。
编译和运行JUnit 4
现在JUnit 4还没有发布编译版本,如果想体验版本的乐趣,则需要从CVS中获取源代码。分支标签是"Version4" (see Resources ).要注意的是大部分文档是根据JUNIT3编写的,还未同步更新。需要Java 5才能编译JUnit 4,因为大量使用了标记,泛型其其它JDK5中的新特性。
执行测试的命令行方式与JUNIT3有点区别,你现在要使用 org.junit.runner.JUnitCore 类进行测试,如下:
$ java -classpath .:junit.jar org.junit.runner.JUnitCore TestA TestB TestC... JUnit version 4.0rc1 Time: 0.003 OK (0 tests) |
兼容性 Beck 和Gamma在努力保持后向和前向兼容性。JUnit 4可以直接运行根据JUNIT3编写的测试类,而不用任何修改,直接将各测试类的全名传递给test runner即可.test runner会根据不同的测试类调用不同的测试框架版本.
后向兼容性有点麻烦,即在JUNIT3中执行根据JUNIT4写的测试类,之所以要这样是因为在一个集成环境如Ecplise中,不需要升级到JUNIT4也可以测试JUNIT4的测试类,从而避免工具IDE的升级。为了让JUNIT4的测试类在JUNI3中能执行,你需要一个适配类 JUnit4TestAdapter 封装JUNIT3的测试类,如下代码:
public static junit.framework.Test suite() { return new JUnit4TestAdapter(AssertionTest.class); } |
而JAVA方面,JUNIT4一点兼容性都没有,因为完全依赖于JDK5的新特性,因此不可能在JAVA1.4上面执行JUNIT4。
还有...
JUnit 4远未结束,还有许多需要补充,如文档,现在不推荐将以前的测试类升级到JUNIT4。当然JUNIT4的开发速度很快,其计划也很快会实现,JAVA1.4的开发人员仍然可以使用JUNIT3.8,而使用JAVA5的人员可以考虑是否采用JUNIT4了,因为在特性上更适合。
资源
- Pragmatic Unit Testing in Java with JUnit (Andy Hunt and Dave Thomas, Pragmatic Programmers, 2003): An excellent introduction to unit testing.
- JUnit Recipes: Practical Methods for Programmer Testing (J. B. Rainsberger, Manning, 2004): One of the most widely cited and referenced books on JUnit.
- TestNG : Cedric Beust's framework pioneered the annotation based testing style now used in JUnit 4.
- " TestNG makes Java unit testing a breeze " (Filippo Diotalevi, developerWorks, January 2005): An introduction to TestNG.
- " Incremental development with Ant and JUnit " (Malcolm Davis, developerWorks, November 2000): Explores the benefits of unit testing, in particular using Ant and JUnit, with code samples.
- " Demystifying Extreme Programming: Test-driven programming " (Roy Miller, developerWorks, April 2003): Find out how test-driven programming can revolutionize your productivity and quality as a programmer, and learn the mechanics of writing tests.
- " Keeping critters out of your code " (David Carew, et. al., developerWorks, June 2003): Learn how you can use JUnit in conjunction with WebSphere Application Developer.
- " Measure test coverage with Cobertura " (Elliotte Rusty Harold, developerWorks, May 2005): Learn to identify untested code and locate bugs with this handy open source tool.
分享到:
相关推荐
下面我们将深入探讨JUnit4的核心概念、功能以及如何使用它。 首先,JUnit4是JUnit系列的一个重大升级,引入了注解(Annotation)的概念,这使得测试用例的编写更为简洁。例如,`@Test`注解用于标记测试方法,`@...
10. **扩展性与兼容性**:JUnit4设计得非常开放,可以通过实现`Runner`接口来扩展其功能,例如SpringJUnit4ClassRunner可以结合Spring框架进行测试。同时,JUnit4与大多数IDE和构建工具(如Maven、Gradle)良好集成...
JUnit4是Java编程语言中最广泛使用的单元测试框架之一,它为开发者提供了编写可重复执行、易于维护的测试代码的能力。这个“junit4 jar包”包含了运行JUnit4测试所必需的库文件,主要包括两个核心组件:`junit-4.11....
### JUnit4 学习知识点详解 #### 一、JUnit4 概述 JUnit4 是 JUnit 测试框架的一个重大更新版本,它充分利用了 Java 5 的注解(Annotation)特性来简化测试用例的编写过程。注解是一种元数据,用于描述程序中的...
JUnit4的设计使其易于与其他库和框架集成,例如Mockito用于模拟对象,PowerMock用于测试静态方法和构造函数,或是TestNG提供更高级的测试功能。 ## 五、持续集成与持续测试 在持续集成环境中,JUnit4可以与Jenkins...
JUnit4是Java编程语言中最广泛使用的单元测试框架之一,它为开发者提供了强大的工具来编写、组织和执行单元测试。JUnit4引入了许多改进和新特性,极大地提升了测试的灵活性和效率。下面将详细介绍JUnit4的关键概念、...
总结来说,JUnit4 是对 JUnit3 的一个重要升级,它利用 Java 5 的注解特性极大地简化了测试用例的编写,提高了测试代码的可读性和可维护性。通过使用注解,开发者能够更自由地组织测试逻辑,同时也能够方便地扩展...
JUnit4 可以应用于各种 Java 项目的测试中,包括单元测试、集成测试、功能测试等。使用 JUnit4 可以简化测试用例的编写,提高测试效率和质量。 六、结论 JUnit4 是 JUnit 框架有史以来的最大改进,主要目标是利用 ...
- `javadoc`目录下的文档提供了JUnit4 API的详细说明,包括类、接口、方法等的用途和用法,是学习和查找特定功能的重要参考。 5. **实际应用**: - **TDD实践**:JUnit4是TDD的主要工具,开发者可以先编写测试,...
赠送jar包:powermock-module-junit4-2.0.9.jar; 赠送原API文档:powermock-module-junit4-2.0.9-javadoc.jar; 赠送源代码:powermock-module-junit4-2.0.9-sources.jar; 赠送Maven依赖信息文件:powermock-...
JUnit4基础文档 单元测试是软件测试的一种,旨在检验软件的正确性和可靠性。JUnit是一个流行的单元测试框架,广泛应用于Java开发中。本文档介绍了JUnit4的基础知识,包括单元测试的概念、JUnit4的HelloWorld示例、...
通过这个“Junit4电子教程 API”,学习者将能够深入理解JUnit4提供的各种功能,并学会如何在实际项目中有效地利用它们。教程可能涵盖如何创建和运行测试,使用断言,处理异常,进行参数化测试,以及如何利用规则和...
这个压缩包文件包含了JUnit4的相关库,使得开发人员能够轻松地在他们的项目中引入单元测试功能。下面我们将深入探讨JUnit4的一些核心概念和功能。 首先,JUnit4是对JUnit3的一个重大改进,它引入了注解...
除了基本的测试功能,JUnit4还提供了丰富的断言库,如`assertEquals()`、`assertTrue()`等,用于检查测试结果是否符合预期。如果测试失败,这些断言会抛出异常,清楚地指出失败的原因。 在实际项目中,开发者通常会...
JUnit4 是一个流行的 Java 单元测试框架,提供了许多功能强大且灵活的测试工具。本文将详细介绍 JUnit4 的使用方法和核心概念。 JUnit4 核心概念 JUnit4 的核心概念包括测试类、测试集和测试运行器。测试类是包含...
除了基本的测试功能,JUnit4还提供了异常测试。`@Test(expected = Exception.class)`注解可用于检查方法是否抛出了预期的异常,这对于验证错误处理逻辑非常有用。 扩展性是JUnit4的一大亮点。通过实现`Rule`接口或...
Junit4作为Java领域最常用的单元测试框架,为开发者提供了方便、高效的测试工具。本文将深入探讨如何使用Junit4对名为Calculate的类进行单元测试,包括其加减乘除四个方法。 首先,我们需要了解Junit4的基本结构和...
相较于早期的JUnit3.8版本,JUnit4引入了许多增强的功能,使得测试更加简洁、灵活和强大。 首先,JUnit4允许我们在测试类中使用注解(Annotation)来定义测试行为。例如,`@BeforeClass`和`@AfterClass`注解分别...
【标题】"junit4 单元测试源码"涉及的是Java编程中单元测试的重要工具JUnit4的使用,这是对代码进行验证和调试的关键部分。JUnit4是JUnit框架的一个版本,它提供了更灵活的注解、测试套件管理和断言方式,使得编写...