TestNG与JUnit4比较

来源:互联网 发布:怎么对数据进行标准化 编辑:程序博客网 时间:2024/05/17 02:38

JUnit 一直 是一个单元测试框架,其构建目的是促进单个对象的测试,它确实能够极其有效地完成此类任务。

而 TestNG 则是用来解决更高 级别的测试问题,因此,它具有 JUnit 中所没有的一些特性。

参数化测试

TestNG 中另一个有趣的特性是参数化测试。在 JUnit 中,如果您想改变某个受测方法的参数组,就只能给每个 不同的参数组编写一个测试用例。多数情况下,这不会带来太多麻烦。然而,我们有时会碰到一些情况,对其中的业务逻辑,需要运行的测试数目变化范围很大。

在这样的情况下,使用 JUnit 的测试人员往往会转而使用 FIT 这样的框架,因为这样就可以用表格数据驱动测试。但是 TestNG 提供了开箱即用的类似特性。通过在 TestNG 的 XML 配置文件中放入参数化数据,就可以对不同的数据集重用同一个测试用例,甚至有可能会得到不同的结果。这种技术完美地避免了只能 假定一切正常的测试,或是没有对边界进行有效验证的情况。

在清单 5 中,我用 Java 1.4 定义了一个 TestNG 测试,该测试可接收两个参数:classnamesize。这两个参数可以验证某个类的层次结构(也就是说,如果传入 java.util.Vector,则 HierarchyBuilder所构建的 Hierarchy 的值将为 2 )。

清单 5. 一个 TestNG 参数化测试
package test.com.acme.da;import com.acme.da.hierarchy.Hierarchy;import com.acme.da.hierarchy.HierarchyBuilder;public class HierarchyTest { /**  * @testng.test  * @testng.parameters value="class_name, size"  */ public void assertValues(String classname, int size) throws Exception{  Hierarchy hier = HierarchyBuilder.buildHierarchy(classname);  assert hier.getHierarchyClassNames().length == size: "didn't equal!"; }}

清单 5 列出了一个泛型测试,它可以采用不同的数据反复重用。请花点时间思考一下这个问题。如果有 10 个不同的参数组合需要在 JUnit 中测试,您只能写 10 个测试用例。每个测试用例完成的任务基本是相同的,只是受测方法的参数有所改变。但是,如果使用参数化测试,就可以只定义一个 测试用例,然后,(举例来说)把所需的参数模式加到 TestNG 的测试套件文件中。清单 6 中展示了这中方法:


清单 6. 一个 TestNG 参数化测试套件文件
<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd"><suite name="Deckt-10"> <test name="Deckt-10-test">  <parameter name="class_name" value="java.util.Vector"/>  <parameter name="size" value="2"/>   <classes>     <class name="test.com.acme.da.HierarchyTest"/>  </classes> </test>  </suite>

清单 6 中的 TestNG 测试套件文件只对该测试定义了一个参数组(class_namejava.util.Vector,且size 等于 2),但却具有无限的可能。这样做的一个额外的好处是:将测试数据移动到 XML 文件的无代码工件就意味着非程序员也可以指定数据。

高级参数化测试

尽管从一个 XML 文件中抽取数据会很方便,但偶尔会有些测试需要有复杂类型,这些类型无法用 String 或原语值来表示。TestNG 可以通过它的@DataProvider 注释处理这样的情况。@DataProvider 注释可以方便地把复杂参数类型映射到某个测试方法。例如,清单 7 中的verifyHierarchy 测试中,我采用了重载的 buildHierarchy 方法,它可接收一个 Class 类型的数据, 它断言(asserting)HierarchygetHierarchyClassNames() 方法应该返回一个适当的字符串数组:


清单 7. TestNG 中的 DataProvider 用法
package test.com.acme.da.ng;import java.util.Vector;import static org.testng.Assert.assertEquals;import org.testng.annotations.DataProvider;import org.testng.annotations.Test;import com.acme.da.hierarchy.Hierarchy;import com.acme.da.hierarchy.HierarchyBuilder;public class HierarchyTest { @DataProvider(name = "class-hierarchies") public Object[][] dataValues(){  return new Object[][]{   {Vector.class, new String[] {"java.util.AbstractList",      "java.util.AbstractCollection"}},   {String.class, new String[] {}}  }; } @Test(dataProvider = "class-hierarchies") public void verifyHierarchy(Class clzz, String[] names)   throws Exception{    Hierarchy hier = HierarchyBuilder.buildHierarchy(clzz);    assertEquals(hier.getHierarchyClassNames(), names,   "values were not equal"); }}

dataValues() 方法通过一个多维数组提供与 verifyHierarchy 测试方法的参数值匹配的数据值。TestNG 遍历这些数据值,并根据数据值调用了两次verifyHierarchy。在第一次调用时,Class 参数被设置为 Vector.class,而 String 数组参数容纳 “java.util.AbstractList ” 和 “ java.util.AbstractCollection” 这两个 String 类型的数据。这样挺方便吧?

为什么只选择其一?

我已经探讨了对我而言,TestNG 的一些独有优势,但是它还有其他几个特性是 JUnit 所不具备的。例如 TestNG 中使用了测试分组,它可以根据诸如运行时间这样的特征来对测试分类。也可在 Java 1.4 中通过 javadoc 风格的注释来使用它,如清单 5 所示。

正如我在本文开头所说,JUnit 4 和 TestNG 在表面上是相似的。然而,设计 JUnit 的目的是为了分析代码单元,而 TestNG 的预期用途则针对高级测试。对于大型测试套件,我们不希望在某一项测试失败时就得重新运行数千项测试,TestNG 的灵活性在这里尤为有用。这两个框架都有自己的优势,您可以随意同时使用它们。