2.3 JUnit测试运行器
当你第一次编写测试时,你希望它们能即简单又快速地运行,将测试作为软件开发生命周期的一部分:编码-运行-测试-编码。可以使用IDEs和编译器快速地构建和运行应用程序;JUnit能让你构建和运行测试。
2.3.1 测试运行器预览
Junit4 可构建向后兼容3.8版本,因为JUnit4.x版本与3.x版本完全不同。它将不仅能执行JUnit4的测试而且也能执行3.x-style测试。这就是为什么最新的JUnit版本提供不同的运行器去运行JUnit3.x的测试、JUnit4测试和不同的测试集。
in table 2.3。JUnit 4 test runners
Runner |
目的 |
org.junit.internal.runners.JUnit38ClassRunner |
这个运行器包括最新的JUnit发布,不仅向后兼容,而且也能将测试用例当作JUnit3.8的测试用例执行 |
org.junit.runners.JUnit4 |
这个运行器将运行测试用例作为Junit4测试用例 |
org.junit.runners.Parameterized |
Parameterized测试运行器运行同一个测试集实用不同的参数 |
org.junit.runners.Suites |
Suite是一个容器,能容纳不同的测试,在一个测试类中Suite能运行@Test注释的方法 |
如果在基本的测试类中没有提供运行器的话,Junit将使用一个默认的测试运行器。假如你希望JUnit使用一个指定的测试运行器。使用@RunWith注释指定测试运行器类。下面的代码演示如何使用:
@RunWith(value=org.junit.internal.runners.JUnit38ClassRunner.class)
public class TestWithJUnit38 extends junit.framework.TestCase{[...]}
现在我们将看到不同测试运行器的预览,如何直接地使用它们。我们将看看到多种测试运行器更详细的内容。
2.3.2 JUnitCore 外观模式(facade)
使测试即简单又快速地运行。JUnit提供了一个外观模式(org.junit.runner.JUnitCore),
能操作任意的测试运行器。JUnit设计这个外观模式去执行测试并收集和统计结果。您能看到JUnitCore类在前面的章节中的figure1.3中。
设计模式实战:外观模式
外观模式是一个设计模式,为子系统中的一组接口提供了一个统一的接口。外观模式定义了一个高层接口,这个接口使得子系统更加容易使用。你能够使用一个外观模式简化许多复杂对象之间的交互,为复杂的子系统调用提供一个统一的入口。
JUnit外观模式决定哪一个运行器执行你的测试。它支持运行JUnit3.8测试、JUnit4测试或者两者混合。
在JUnit4之前,JUnit包括Swing和AWT测试运行器;但是现在不在包括。这些图形测试运行器在屏幕上显示进度条,就像著名的JUnit绿色条(green bar)。JUnit测试者们倾向于参考green bar表示测试通过,red bar表示测试失败。“Keep the bar green to keep the code clean”,这是JUnit的格言。
图2.1展示Eclipse JUnit 视图运行测试后的一个绿色条(Green bar)。
所有流行的IDE工具都支持集成JUnit。
2.3.3自定义测试运行器
不像其它JUnit框架的元素,这里没有Runner接口,而是各种测试运行器处理都是继承JUnit中org.junit.rnner.Runner类。创建你自己的测试运行器,你将需要继承Runner类,请参考附录B,那里将负责更详细的主题。
Figure2.1 junit's green bar, shown in Eclipse.
2.4构成测试套件
对于一个简单的测试,你能编译简单的计算测试程序从Listing2.1,可以使用外观模式转换处理。就像这样:
>java org.junit.runner.JUnitCore CalculatorTest
这个测试将运行良好,假设classpath路径已配置正确。这足够简单--至少到目前为止,关注的是运行一个单独的测试用例。
2.4.1 将测试用例构成测试套件
下一步将运行更多的测试类,为了使这个任务更容易,JUnit提供了测试套件Suite,这个Suite是一个容器,用于聚集测试,目的是分组和调用。
Junit设计Suite运行一个或多个测试用例,测试运行器启动Suite,Suite决定运行哪一个测试用例。
在第一章结尾时,你可能想知道如何管理测试用例的运行。当你没有定义一个Suite时,保持简单的事情简单化,如果你没有提供的话,测试运行器自动地创建一个Suite。
默认的Suite扫描你的测试类中任何使用@Test注释的方法,本质上,默认的suite为每一个@Test注释的方法创建了一个你测试类的实例。Junit然后执行每个@Test注释的方法,使各个方法彼此独立以免产生潜在的影响。
假如你添加另外的测试给CalculatorTest类,像testSubtract,使用@Test注释,默认的Suite将自动地将它包括在内。
Suite对象是一个运行器,在测试类中执行所有@Test注释的方法,Listing2.3展示如何将多个测试用例构成一独立的测试套件test Suite。
Listing 2.3 Composing a Suite from test classes
[...]
@RunWith(value=org.junit.runners.Suite.class)
@SuiteClasses(value={folderconfiguratinTest.class,FileconfigurationTest.class})
public class FileSystemConfigurationTestSuite{}
In Listing2.3,在这个测试中,我们使用@RunWith注释指定合适的运行器,使用
@SuiteClasses注释指定测试包括测试类列表。所有来自测试用例@Test注释的方法将包括在测试套件中。
对于CalculatorTest在Listing2.1,你能展现默认的Suite像如下:
@RunWith(value=Suite.class)
@SuiteClasses(value={CalculatorTest.class})
public class AllTests{}
2.4.2 将测试套件构成更大的套件
因为JUnit构建了智能的方法,它可以去创建套件的套件,例如Listing2.4,把各种文件联系起来展示测试用例如何组成套件,这反而构成了一个主套件(master Suite)
Listing 2.4 Suite of suites
[...]
public class TestCaseA{
@Test
public void testA1(){
//omitted
}
}
[...]
public class TestCaseB{
@Test
public void testB1(){
//omitted
}
}
[...]
@runWith(value=suite.class)
@suiteClasses(value={testCasea.class})
public class TestsuiteA{
}
[...]
@RunWith(value=Suite.class)
@SuiteClasses(value={TestCaseB.class})
public class TestsuiteB{
}
[...]
@RunWith(value=Suite.class)
@SuiteClasses(value={TestSuiteA.class,TestSuiteB.class})
public class MasterTestSuite{
}
两个简单测试套件TestSuiteA和TestSuiteB每个都只有一个测试用例。这个例子是个简化的缩写。一个真正的套件将包括多个测试用例,就像我们的主套件一样。
你能运行任意的JUnit测试用例在列表中,其中一个测试用例,一个测试套件,一个主套件,Figure2.2显示使用Eclipse运行主套件的结果,测试套件提供一个强大的方法来组织测试,这个便利不是JUnit独有的,你将在下部分看到,这使得我们将重新考虑创建任何JUnit套件。
2.4.3 套件,IDEs,Ant,和Maven
Ant和Maven也提供指定方法组织测试用例和套件,使用正则表达式的形式运行测试用例和套件。此外,IDEs像Eclipse允许你运行所有的测试用例和套件在一个选择的包或者资源目录中。这足够使我们重新考虑首次创建JUnit Suites是否值得。
JUnit Suites很有用,假如你想要在Java中组织你们测试。它独立的能力无关你的构建系统,因为它通常为某人或某团体除了开发者来维护构建版本。相似地,你可能希望提供独立的集成能力从任何给定的IDE和JUnit中。
Figure 2.2 Running a suite of suites in Eclipse
2.5 总结
在这章中,我们介绍了JUnit核心概念和测试用例,我们向你展示如何理解测试用例(test
class),测试套件(Suite),测试运行器(Runner)。
使用一个测试用例测试一个领域对象,每一个测试方法聚焦一个领域对象或者一个特定的方法集,JUnit4广泛使用注释(annotation)去定义和管理测试。JUnit4使JUnit3中一个测试类必须是TestCase的子类的形式过时了。
使用测试套件将相关的测试用例组织在一起。允许你直接调用一个组,也能使用更高层的套件将多个套件组织在一起。
你使用一个Runner处理单元测试和测试套件。
在下一章中,我们将介绍控制器设计模式和构建一个简单的控制器组件应用使用JUnit,这样,我们不仅展示如何使用我们到目前讨论的JUnit组件,而且会介绍更过的JUnit最佳实践。