1. 概述
在本文中,我们将介绍TestNG测试框架。
我们将重点介绍:框架设置、编写简单的测试用例和配置、测试执行、测试报告生成和并发测试执行。
2. 设置
让我们首先在pom.xml文件中添加Maven依赖项:
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.1.0</version>
<scope>test</scope>
</dependency>
最新版本可以在Maven仓库中找到。
使用Eclipse时,可以从Eclipse Marketplace下载并安装TestNG插件。
3. 编写测试用例
要使用TestNG编写测试,我们只需要使用org.testng.annotations.Test注解对测试方法进行标注:
@Test
public void givenNumber_whenEven_thenTrue() {
assertTrue(number % 2 == 0);
}
4. 测试配置
在编写测试用例时,我们通常需要在测试执行之前执行一些配置或初始化指令,以及在测试完成后进行一些清理。TestNG在方法、类、组和套件级别提供了许多初始化和清理功能:
@BeforeClass
public void setup() {
number = 12;
}
@AfterClass
public void tearDown() {
number = 0;
}
使用@BeforeClass注解标注的setup()方法将在执行该测试类的任何方法之前被调用,并且在执行该测试类的所有方法之后调用tearDown()。
同样,我们可以在方法、组、测试和套件级别的任何配置中使用@BeforeMethod/@AfterMethod、@Before/AfterGroup、@Before/AfterTest和@Before/AfterSuite注解。
5. 测试执行
我们可以使用Maven的“test”命令运行测试用例,它将执行所有带有@Test注解的测试用例,并将它们放入默认的测试套件中。我们还可以使用maven-surefire-plugin从TestNG测试套件XML文件运行测试用例:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>
src\test\resources\test_suite.xml
</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
请注意,如果我们有多个涵盖所有测试用例的XML文件,我们可以将它们全部添加到suiteXmlFiles标签中:
<suiteXmlFiles>
<suiteXmlFile>
src/test/resources/parametrized_test.xml
</suiteXmlFile>
<suiteXmlFile>
src/test/resources/registration_test.xml
</suiteXmlFile>
</suiteXmlFiles>
为了独立运行测试,我们需要在类路径中包含TestNG库和编译的测试类以及XML配置文件:
java org.testng.TestNG test_suite.xml
6. 分组测试
测试可以分组运行,例如,在50个测试用例中,可以将每15个组合在一起并执行,而其他测试用例保持不变。
在TestNG中,套件中的分组测试是使用XML文件完成的:
<suite name="suite">
<test name="test suite">
<classes>
<class name="cn.tuyucheng.taketoday.RegistrationTest"/>
<class name="cn.tuyucheng.taketoday.SignInTest"/>
</classes>
</test>
</suite>
请注意,两个测试类RegistrationTest、SignInTest现在属于同一个套件,一旦执行套件,该类中的测试用例将被执行。
除了测试套件,我们还可以在TestNG中创建测试组,而不是测试类方法被组合在一起。为此,请在@Test注解中添加groups参数:
@Test(groups = "regression")
public void givenNegativeNumber_sumLessthanZero_thenCorrect() {
int sum = numbers.stream().reduce(0, Integer::sum);
assertTrue(sum < 0);
}
让我们使用XML来执行组:
<test name="test groups">
<groups>
<run>
<include name="regression"/>
</run>
</groups>
<classes>
<class
name="cn.tuyucheng.taketoday.SummationServiceTest"/>
</classes>
</test>
这将在SummationServiceTest类中执行标记为regression组的测试方法。
7. 参数化测试
参数化单元测试用于在多种条件下测试相同的代码。借助参数化单元测试,我们可以设置一个从某个数据源获取数据的测试方法。主要思想是使单元测试方法可重用并使用不同的输入集进行测试。
在TestNG中,我们可以使用@Parameter或@DataProvider注解对测试进行参数化。在使用XML文件时,使用@Parameter标注测试方法:
@Test
@Parameters({"value", "isEven"})
public void givenNumberFromXML_ifEvenCheckOK_thenCorrect(int value, boolean isEven) {
assertEquals(isEven, value % 2 == 0);
}
并使用XML文件提供数据:
<suite name="My test suite">
<test name="numbersXML">
<parameter name="value" value="1"/>
<parameter name="isEven" value="false"/>
<classes>
<class name="cn.tuyucheng.taketoday.ParametrizedTests"/>
</classes>
</test>
</suite>
使用XML文件中的数据很有用,但我们通常需要更复杂的数据。@DataProvider注解用于处理这些场景,可用于映射复杂的参数类型以供测试方法使用。@DataProvider用于原始数据类型:
@DataProvider(name = "numbers")
public static Object[][] evenNumbers() {
return new Object[][]{{1, false}, {2, true}, {4, true}};
}
@Test(dataProvider = "numbers")
public void givenNumberFromDataProvider_ifEvenCheckOK_thenCorrect(Integer number, boolean expected) {
assertEquals(expected, number % 2 == 0);
}
@DataProvider用于对象类型:
@Test(dataProvider = "numbersObject")
public void givenNumberObjectFromDataProvider_ifEvenCheckOK_thenCorrect(EvenNumber number) {
assertEquals(number.isEven(), number.getValue() % 2 == 0);
}
@DataProvider(name = "numbersObject")
public Object[][] parameterProvider() {
return new Object[][]{{new EvenNumber(1, false)}, {new EvenNumber(2, true)}, {new EvenNumber(4, true)}};
}
使用它,可以在测试中创建和使用任何必须测试的对象。这对于集成测试用例非常有用。
8. 忽略测试用例
我们有时希望在开发过程中暂时不执行某个测试用例。这可以通过在@Test注解中添加enabled=false来完成:
@Test(enabled=false)
public void givenNumbers_sumEquals_thenCorrect() {
int sum = numbers.stream.reduce(0, Integer::sum);
assertEquals(6, sum);
}
9. 依赖性测试
让我们考虑一个场景,如果初始测试用例失败,所有后续测试用例都应该被执行,而不是被标记为跳过。TestNG通过@Test注解的dependsOnMethods参数提供了这个功能:
@Test
public void givenEmail_ifValid_thenTrue() {
boolean valid = email.contains("@");
assertEquals(valid, true);
}
@Test(dependsOnMethods = {"givenEmail_ifValid_thenTrue"})
public void givenValidEmail_whenLoggedIn_thenTrue() {
LOGGER.info("Email {} valid >> logging in", email);
}
请注意,登录测试用例依赖于电子邮件验证测试用例。因此,如果电子邮件验证失败,将跳过登录测试。
10. 并发测试执行
TestNG允许测试以并行或多线程模式运行,从而提供了一种测试这些多线程代码片段的方法。
你可以将方法、类和套件配置为在它们自己的线程中运行,从而减少总执行时间。
10.1 并行的类和方法
要并行运行测试类,请在XML配置文件的suite标签中指定parallel属性,并通过classes属性指定测试类:
<suite name="suite" parallel="classes" thread-count="2">
<test name="test suite">
<classes>
<class name="cn.tuyucheng.taketoday.RegistrationTest"/>
<class name="cn.tuyucheng.taketoday.SignInTest"/>
</classes>
</test>
</suite>
请注意,如果我们在XML文件中有多个test标签,这些测试也可以通过指定parallel=”tests”并行运行。同样要并行执行单个方法,请指定parallel=”methods”。
10.2 测试方法的多线程执行
假设我们需要测试代码在多个线程中运行时的行为。TestNG允许在多个线程中运行一个测试方法:
public class MultiThreadedTests {
@Test(threadPoolSize = 5, invocationCount = 10, timeOut = 1000)
public void givenMethod_whenRunInThreads_thenCorrect() {
int count = Thread.activeCount();
assertTrue(count > 1);
}
}
threadPoolSize表示该方法将在n个线程中运行,如上所述。invocationCount和timeOut表示测试将被执行多次,如果测试需要更多时间,则测试失败。
11. 功能测试
TestNG具有可用于功能测试的功能。与Selenium结合使用,它既可以用于测试Web应用程序的功能,也可以用于使用HttpClient测试Web服务。
有关使用Selenium和TestNG进行功能测试的更多详细信息,请参见此处。本文中还有一些关于集成测试的内容。
12. 总结
在本文中,我们快速介绍了如何设置TestNG并执行简单的测试用例、生成报告、测试用例的并发执行以及一些关于函数式编程的知识。有关依赖测试、忽略测试用例、测试组和套件等更多功能,你可以在此处参考我们的JUnit与TestNG文章。
与往常一样,本教程的完整源代码可在GitHub上获得。