TestNG教程
TestNG是一个受JUnit和NUnit启发的Java应用程序测试框架。
测试NG
TestNG提供了许多功能,使编写和运行测试用例变得容易:
基于注释
适用于主要IDE(例如Eclipse和IDEA)的插件。
自动创建测试套件
基于HTML的报告生成
能够使用IDE插件运行单一测试方法。
使用@DataProvider进行数据驱动的测试
无需其他依赖来运行和记录
TestNG XML文件以运行具有不同配置的测试套件
TestNG Maven依赖
TestNG库存在于maven存储库中,您可以在maven依赖项下面添加以在您的项目中包含TestNG。
<dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>6.14.3</version> <scope>test</scope> </dependency>
TestNG Eclipse插件
我正在使用Eclipse for TestNG示例项目,因此我们首先安装TestNG Eclipse插件。
转到" Eclipse Marketplace"并搜索" TestNG"。
单击"安装",然后通过其他屏幕进行安装。
安装完成后,您将必须接受其许可协议并重新启动Eclipse。
转到"窗口|显示视图其他"和" Java"中,您应该看到" TestNG"。
这意味着TestNG for Eclipse已成功安装,并且我们准备创建TestNG测试类。
创建TestNG类
在资源管理器中转到您的项目,然后单击"新建|其他",然后选择" TestNG类",然后单击下一步。
在下一个屏幕中,我们必须指定我们的TestNG类配置,并选择要包括在类中的注释,然后单击"完成"按钮。
这将生成如下的TestNG骨架类。
package com.theitroad.utils; import org.testng.annotations.Test; import org.testng.annotations.BeforeMethod; import org.testng.annotations.AfterMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.BeforeClass; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeTest; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeSuite; import org.testng.annotations.AfterSuite; public class TestUtils { @Test(dataProvider = "dp") public void f(Integer n, String s) { } @BeforeMethod public void beforeMethod() { } @AfterMethod public void afterMethod() { } @DataProvider public Object[][] dp() { return new Object[][] { new Object[] { 1, "a" }, new Object[] { 2, "b" }, }; } @BeforeClass public void beforeClass() { } @AfterClass public void afterClass() { } @BeforeTest public void beforeTest() { } @AfterTest public void afterTest() { } @BeforeSuite public void beforeSuite() { } @AfterSuite public void afterSuite() { } }
就是这样,我们可以通过运行"运行方式| TestNG测试",如下图所示。
由于我们的测试类没有任何内容,因此它应该通过所有测试。
您可以检查"控制台"中生成的日志," TestNG View"将向您显示测试运行的基本详细信息。
TestNG测试套件流程
我在带注释的方法中添加了一些控制台日志记录,以了解TestNG测试运行的流程。
package com.theitroad.utils; import org.testng.annotations.Test; import org.testng.annotations.BeforeMethod; import org.testng.annotations.AfterMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.BeforeClass; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeTest; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeSuite; import org.testng.annotations.AfterSuite; public class TestUtils { @Test(dataProvider = "dp") public void f(Integer n, String s) { System.out.println("Inside @Test"); } @BeforeMethod public void beforeMethod() { System.out.println("Inside @BeforeMethod"); } @AfterMethod public void afterMethod() { System.out.println("Inside @AfterMethod"); } @DataProvider public Object[][] dp() { System.out.println("Inside @DataProvider"); return new Object[][] { new Object[] { 1, "a" }, new Object[] { 2, "b" }, }; } @BeforeClass public void beforeClass() { System.out.println("Inside @BeforeClass"); } @AfterClass public void afterClass() { System.out.println("Inside @AfterClass"); } @BeforeTest public void beforeTest() { System.out.println("Inside @BeforeTest"); } @AfterTest public void afterTest() { System.out.println("Inside @AfterTest"); } @BeforeSuite public void beforeSuite() { System.out.println("Inside @BeforeSuite"); } @AfterSuite public void afterSuite() { System.out.println("Inside @AfterSuite"); } }
当我再次运行它时,在控制台日志下面生成。
[RemoteTestNG] detected TestNG version 6.14.3 Inside @BeforeSuite Inside @BeforeTest Inside @BeforeClass Inside @DataProvider Inside @BeforeMethod Inside @Test Inside @AfterMethod Inside @BeforeMethod Inside @Test Inside @AfterMethod Inside @AfterClass Inside @AfterTest PASSED: f(1, "a") PASSED: f(2, "b") =============================================== Default test Tests run: 2, Failures: 0, Skips: 0 =============================================== Inside @AfterSuite =============================================== Default suite Total tests run: 2, Failures: 0, Skips: 0 ===============================================
根据以上输出,我们可以得出TestNG测试的流程为:
BeforeSuite -> BeforeTest -> BeforeClass -> DataProvider -> { BeforeMethod -> Test -> AfterMethod } * N -> AfterClass -> AfterTest -> AfterSuite
N是测试方法执行的次数,它取决于@DataProvider方法生成的输入次数。
我们可以使用@BeforeXXX方法来进行一些预处理,并初始化要在测试套件中使用的资源。
同样,我们可以使用@AfterXXX方法来进行后处理和关闭资源。
TestNG教程
现在,我们已经了解了TestNG的基础知识并在Eclipse中进行了设置,让我们创建一个几乎没有方法的类,并使用TestNG在其上运行一些测试案例。
package com.theitroad.utils; public class Utils { public static String NAME = ""; public int add(int x, int y) { return x + y; } public int subtract(int x, int y) { return x - y; } public static void setName(String s) { System.out.println("Setting NAME to " + s); NAME = s; } }
我还添加了一些公共方法,静态方法和无效方法。
下面是我的TestNG类,用于测试这些方法。
package com.theitroad.utils; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class TestUtils { @Test(dataProvider = "dp") public void test_add(Integer x, Integer y) { Utils u = new Utils(); Assert.assertEquals(u.add(x, y), x + y); } @Test(dataProvider = "dp") public void test_subtract(Integer x, Integer y) { Utils u = new Utils(); Assert.assertEquals(u.subtract(x, y), x - y); } @Test(dataProvider = "dpName") public void test_setName(String s) { Utils.setName(s); Assert.assertEquals(Utils.NAME, s); } @DataProvider public Object[][] dp() { return new Object[][] { new Object[] { 1, 1 }, new Object[] { 2, 2 }, }; } @DataProvider public Object[][] dpName() { return new Object[][] { new Object[] { "Utils" }, new Object[] { "MyUtils" }, }; } }
现在,当我们在类上方运行TestNG Test时,将在控制台中获得以下输出。
[RemoteTestNG] detected TestNG version 6.14.3 Setting NAME to Utils Setting NAME to MyUtils PASSED: test_add(1, 1) PASSED: test_add(2, 2) PASSED: test_setName("Utils") PASSED: test_setName("MyUtils") PASSED: test_subtract(1, 1) PASSED: test_subtract(2, 2) =============================================== Default test Tests run: 6, Failures: 0, Skips: 0 =============================================== =============================================== Default suite Total tests run: 6, Failures: 0, Skips: 0 ===============================================
刷新项目,您将看到一个新生成的目录" test-output"。
在任何浏览器中打开index.html
,您将看到如下图所示HTML报告。
TestNG XML套件
TestNG最好的部分之一是自动生成测试套件xml文件。
我们可以对其进行编辑并添加参数,也可以使用它来运行单个测试方法。
TestNG XML套件提供了很多选项,当您想通过命令行运行测试用例(例如在没有Eclipse的服务器上)时,它非常有用。
我们可以使用以下命令运行TestNG测试套件xml文件:
$java com.theitroad.utils.TestUtils testng.xml
TestNG XML是一个非常广泛的主题,如果您想探索更多内容,请阅读其文档。
TestNG运行单一测试方法
我们也可以运行一个测试方法,当我们的测试类有很多方法并且我们只想测试其中一些方法时,这将非常有用。
TestNG测试失败
让我们看看在代码中引入错误后会发生什么,请如下更改" Utils"类" setName"方法。
public static void setName(String s) { System.out.println("Setting NAME to " + s); //NAME = s; //introducing bug intentionally }
现在,当我们再次运行测试类时,将在控制台中获得以下输出。
[RemoteTestNG] detected TestNG version 6.14.3 Setting NAME to Utils Setting NAME to MyUtils FAILED: test_setName("Utils") java.lang.AssertionError: expected [Utils] but found [] at org.testng.Assert.fail(Assert.java:96) at org.testng.Assert.failNotEquals(Assert.java:776) at org.testng.Assert.assertEqualsImpl(Assert.java:137) at org.testng.Assert.assertEquals(Assert.java:118) at org.testng.Assert.assertEquals(Assert.java:453) at org.testng.Assert.assertEquals(Assert.java:463) at com.theitroad.utils.TestUtils.test_setName(TestUtils.java:23) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:564) at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:124) at org.testng.internal.Invoker.invokeMethod(Invoker.java:583) at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:719) at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:989) at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125) at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109) at org.testng.TestRunner.privateRun(TestRunner.java:648) at org.testng.TestRunner.run(TestRunner.java:505) at org.testng.SuiteRunner.runTest(SuiteRunner.java:455) at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450) at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415) at org.testng.SuiteRunner.run(SuiteRunner.java:364) at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84) at org.testng.TestNG.runSuitesSequentially(TestNG.java:1208) at org.testng.TestNG.runSuitesLocally(TestNG.java:1137) at org.testng.TestNG.runSuites(TestNG.java:1049) at org.testng.TestNG.run(TestNG.java:1017) at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:114) at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251) at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77) FAILED: test_setName("MyUtils") java.lang.AssertionError: expected [MyUtils] but found [] at org.testng.Assert.fail(Assert.java:96) at org.testng.Assert.failNotEquals(Assert.java:776) at org.testng.Assert.assertEqualsImpl(Assert.java:137) at org.testng.Assert.assertEquals(Assert.java:118) at org.testng.Assert.assertEquals(Assert.java:453) at org.testng.Assert.assertEquals(Assert.java:463) at com.theitroad.utils.TestUtils.test_setName(TestUtils.java:23) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:564) at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:124) at org.testng.internal.Invoker.invokeMethod(Invoker.java:583) at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:719) at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:989) at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125) at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109) at org.testng.TestRunner.privateRun(TestRunner.java:648) at org.testng.TestRunner.run(TestRunner.java:505) at org.testng.SuiteRunner.runTest(SuiteRunner.java:455) at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450) at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415) at org.testng.SuiteRunner.run(SuiteRunner.java:364) at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84) at org.testng.TestNG.runSuitesSequentially(TestNG.java:1208) at org.testng.TestNG.runSuitesLocally(TestNG.java:1137) at org.testng.TestNG.runSuites(TestNG.java:1049) at org.testng.TestNG.run(TestNG.java:1017) at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:114) at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251) at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77)
您是否注意到我仅在setName方法上运行测试。
:)
从命令行运行TestNG测试
可以从Eclipse运行我们的测试用例很好,但是在大多数情况下,我们在构建项目时要运行项目的所有测试用例。
好吧,Maven会自动为我们运行测试用例。
下图显示了mvn clean install
命令的输出。
TestNG测试用例顺序
TestNG测试用例按其方法名称的顺序运行。
因此,在我们的情况下,执行顺序为:test_add-> test_setName-> test_subtract
。
我们可以通过设置测试方法的"优先级"来更改顺序。
如果我们希望执行顺序为test_add-> test_subtract-> test_setName
,那么我们可以像下面这样更改@Test批注。
@Test(dataProvider = "dp", priority=1) public void test_add(Integer x, Integer y) { } @Test(dataProvider = "dp", priority=2) public void test_subtract(Integer x, Integer y) { } @Test(dataProvider = "dpName", priority=3) public void test_setName(String s) { }
请注意,优先级较低的方法将首先执行。