Junit 4 和 TestNG 都是 Java 方面非常流行的单元测试框架。在功能上两个框架都非常类似。到底哪个比较好?在Java项目中我们应该选择哪个框架?
下图将会对Junit 4 和 TestNG 做个功能特征的对比。
注解支持
Junit 4 和 TestNG 在注解方面的实现非常相似。
特性 | JUnit 4 | TestNG |
测试注解 | @Test | @Test |
测试套件在执行之前需要执行的 | – | @BeforeSuite |
测试套件在执行之后需要执行的 | – | @AfterSuite |
在测试之前需要执行的 | – | @BeforeTest |
在测试之后需要执行的 | – | @AfterTest |
在一个测试方法所属于的任意一个组的第一个方法被调用之前执行 | – | @BeforeGroups |
在一个测试方法所属于的任意一个组的最后一个方法被调用之后执行 | – | @AfterGroups |
在当前类的第一个测试方法调用之前执行 | @BeforeClass | @BeforeClass |
在当前类的最后一个测试方法调用之后执行 | @AfterClass | @AfterClass |
每个测试方法之前需要执行 | @Before | @BeforeMethod |
每个测试方法之后需要执行 | @After | @AfterMethod |
忽略 | @ignore | @Test(enabled=false) |
预期异常 | @Test(expected = ArithmeticException.class) | @Test(expectedExceptions = ArithmeticException.class) |
超时 | @Test(timeout = 1000) | @Test(timeout = 1000) |
JUnit 4 和 TestNG 之间注解方面的区别主要有以下几点:
- 在Junit 4 中,如果我们需要在方法前面使用
@BeforeClass
和@AfterClass
,那么该测试方法则必须是静态方法。TestNG 在方法定义部分则更加的灵活,它不需要类似的约束。 - 3个附加的setUp/tearDown级别:套件和分组(@Before/AfterSuite, @Before/AfterTest, @Before/AfterGroup)。想了解详细的请看这里
JUnit 4
@BeforeClasspublicstaticvoidoneTimeSetUp(){// one-time initialization codeSystem.out.println("@BeforeClass - oneTimeSetUp");}
TestNG
@BeforeClasspublicvoidoneTimeSetUp(){// one-time initialization codeSystem.out.println("@BeforeClass - oneTimeSetUp");}
在Junit 4中,注解的命名是比较令人困惑的,例如 Before
, After
and Expected
,我们不是很确切的能理解在方法前面有Before
和After
这样的注解是做什么的,同样Expected
也如此。TestNG在这方面做的就好很多,注解使用了BeforeMethod
,AfterMethod
和ExpectedException
,这样的名字就非常好理解了。
异常测试
异常测试的意思是在单元测试中应该抛出什么异常是合理的,这个特性在两个框架都已经实现。
JUnit 4
@Test(expected=ArithmeticException.class)publicvoiddivisionWithException(){inti=1/0;}
TestNG
@Test(expectedExceptions=ArithmeticException.class)publicvoiddivisionWithException(){inti=1/0;}
忽略测试
忽略测试意思是在单元测试哪些是可以被忽略的,这个特性在两个框架都已经实现。
JUnit 4
@Ignore("Not Ready to Run")@TestpublicvoiddivisionWithException(){System.out.println("Method is not ready yet");}
TestNG
@Test(enabled=false)publicvoiddivisionWithException(){System.out.println("Method is not ready yet");}
时间测试
时间测试意思是如果一个单元测试运行的时间超过了一个指定的毫秒数,那么测试将终止并且标记为失败的测试,这个特性在两个框架都已经实现。
JUnit 4
@Test(timeout=1000)publicvoidinfinity(){while(true);}
TestNG
@Test(timeOut=1000)publicvoidinfinity(){while(true);}
套件测试
套件测试就是把几个单元测试组合成一个模块,然后运行,这个特性两个框架均已实现。然而却是用了两个不同的方式来实现的。
JUnit 4
@RunWith
和 @Suite
注解被用于执行套件测试。下面的代码是所展示的是在JunitTest5
被执行之后需要JunitTest1
和 JunitTest2
也一起执行。所有的声明需要在类内部完成。
@RunWith(Suite.class)@Suite.SuiteClasses({JunitTest1.class,JunitTest2.class})publicclassJunitTest5{}
TestNG
执行套件测试是使用XML文件配置的方式来做。下面的 XML 的文件可以使得TestNGTest1
和TestNGTest2
一起执行。
<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" ><suitename="My test suite"><testname="testing"><classes><classname="com.fsecure.demo.testng.TestNGTest1"/><classname="com.fsecure.demo.testng.TestNGTest2"/></classes></test></suite>
TestNG可以在这块做的更好,使用了组
的概念,每个方法都可以被分配到一个组里面,可以根据功能特性来分组。例如:
这是一个有4个方法,3个组(method1, method2 和 method4)的类
@Test(groups="method1")publicvoidtestingMethod1(){System.out.println("Method - testingMethod1()");}@Test(groups="method2")publicvoidtestingMethod2(){System.out.println("Method - testingMethod2()");}@Test(groups="method1")publicvoidtestingMethod1_1(){System.out.println("Method - testingMethod1_1()");}@Test(groups="method4")publicvoidtestingMethod4(){System.out.println("Method - testingMethod4()");}
下面XML文件定义了一个只是执行methed1
的组的单元测试
<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" ><suitename="My test suite"><testname="testing"><groups><run><includename="method1"/></run></groups><classes><classname="com.fsecure.demo.testng.TestNGTest5_2_0"/></classes></test></suite>
使用分组的概念,集成测试就会更加强大。例如,我们可以只是执行所有测试中的组名为DatabaseFuntion
的测试。
参数化测试
参数化测试意思是给单元测试传多个参数值。这个特性在JUnit 4 和TestNG。然后两个框架实现的方式却完全不同。
JUnit 4
@RunWith
和 @Parameter
注解用于为单元测试提供参数值,@Parameters
必须返回 List[],参数将会被作为参数传给类的构造函数。
@RunWith(value=Parameterized.class)publicclassJunitTest6{privateintnumber;publicJunitTest6(intnumber){this.number=number;}@ParameterspublicstaticCollection<Object[]>data(){Object[][]data=newObject[][]{{1},{2},{3},{4}};returnArrays.asList(data);}@TestpublicvoidpushTest(){System.out.println("Parameterized Number is : "+number);}}
它在使用上有许多的限制;我们必须遵循 JUnit 的方式去声明参数,参数必须通过构造函数的参数去初始化类的成员来用于测试。返回的参数类型必须是List []
,数据已经被限定为String或者是一个原始值。
TestNG
使用XML文件或者@DataProvider
注解来给测试提供参数。
XML文件配置参数化测试
只是在方法上声明@Parameters
注解,参数的数据将由 TestNG 的 XML 配置文件提供。这样做之后,我们可以使用不同的数据集甚至是不同的结果集来重用一个测试用例。另外,甚至是最终用户,QA 或者 QE 可以提供使用 XML 文件来提供他们自己的数据来做测试。
Unit Test
publicclassTestNGTest6_1_0{@Test@Parameters(value="number")publicvoidparameterIntTest(intnumber){System.out.println("Parameterized Number is : "+number);}}
XML 文件