TestNG教程

时间:2020-02-23 14:41:57  来源:igfitidea点击:

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) {
}

请注意,优先级较低的方法将首先执行。