Introduction to TestNG – TestNG简介

最后修改: 2017年 3月 28日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this article, we’ll introduce the TestNG testing framework.

在这篇文章中,我们将介绍TestNG的测试框架。

We’ll focus on: framework setup, writing simple test case and configuration, test execution, test reports generation, and concurrent test execution.

我们将专注于:框架设置,编写简单的测试案例和配置,测试执行,测试报告的生成,以及并发的测试执行。

2. Setup

2.设置

Let’s start by adding the Maven dependency in our pom.xml file:

我们先在pom.xml文件中添加Maven的依赖性。

<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>7.1.0</version>
    <scope>test</scope>
</dependency>

The latest version can be found in the Maven repository.

最新版本可以在Maven资源库中找到。

When using Eclipse, the TestNG plugin may be downloaded and installed from the Eclipse Marketplace.

当使用Eclipse时,TestNG插件可以从Eclipse Marketplace下载和安装。

3. Writing a Test Case

3.编写测试案例</strong

To write a test using TestNG, we just need to annotate the test method with org.testng.annotations.Test annotation:

要使用TestNG写一个测试,我们只需要用org.testng.annotations.Testannotation来注解测试方法。

@Test
public void givenNumber_whenEven_thenTrue() {
    assertTrue(number % 2 == 0);
}

4. Test Configurations

4.测试配置

While writing test cases, often we need to execute some configuration or initialization instructions before test executions, and also some cleanup after completion of tests. TestNG provides a number of initialization and clean-up features at method, class, group and suite levels:

在编写测试用例时,我们经常需要在测试执行前执行一些配置或初始化指令,也需要在测试完成后进行一些清理。TestNG在方法、类、组和套件层面提供了一些初始化和清理功能。

@BeforeClass
public void setup() {
    number = 12;
}

@AfterClass
public void tearDown() {
    number = 0;
}

The setup() method annotated with @BeforeClass annotations will be invoked before execution of any methods of that test class, and tearDown() after execution all methods of the test class.

带有@BeforeClass注解的setup()方法将在执行该测试类的任何方法之前被调用,而tearDown()则在执行测试类的所有方法之后。

Similarly, we can use the @BeforeMethod, @AfterMethod, @Before/AfterGroup, @Before/AfterTest and @Before/AfterSuite annotations for any configuration at method, group, test and suite levels.

同样地,我们可以使用@BeforeMethod, @AfterMethod, @Before/AfterGroup, @Before/AfterTest @Before/AfterSuite 注解,用于方法、组、测试和套件级别的任何配置。

5. Test Execution

5.测试执行

We can run the test cases with Maven’s “test” command, it will execute all the test cases annotated with @Test putting them to a default test suite. We can also run test cases from the TestNG test suite XML files, by using the maven-surefire-plugin:

我们可以用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>

Note that if we have multiple XML files, covering all test cases, we can add all of them in the suiteXmlFiles tag:

注意,如果我们有多个XML文件,涵盖所有的测试案例,我们可以在suiteXmlFilestag中添加所有的文件。

<suiteXmlFiles>
    <suiteXmlFile>
      src/test/resources/parametrized_test.xml
    </suiteXmlFile>
    <suiteXmlFile>
      src/test/resources/registration_test.xml
    </suiteXmlFile>
</suiteXmlFiles>

In order to run the test standalone, we need to have the TestNG library in the classpath and the compiled test class along with the XML configuration file:

为了独立运行测试,我们需要在classpath中拥有TestNG库,并将编译后的测试类与XML配置文件一起。

java org.testng.TestNG test_suite.xml

6. Grouping Tests

6.分组测试

Tests can be run in groups, for example out of 50 test cases 15 can be grouped together and executed leaving others as is.

测试可以分组运行,例如在50个测试用例中,有15个可以分组执行,其他的则保持原样。

In TestNG grouping tests in suites are done using XML file:

在TestNG中,测试套件的分组是通过XML文件完成的。

<suite name="suite">
    <test name="test suite">
        <classes>
            <class name="com.baeldung.RegistrationTest" />
            <class name="com.baeldung.SignInTest" />
        </classes>
    </test>
</suite>

Notice that, both the test classes RegistrationTest, SignInTest now belongs to the same suite and once suite is executed, test cases in this class will get executed.

注意,两个测试类RegistrationTest, SignInTest现在都属于同一个套件,一旦套件被执行,这个类的测试用例就会被执行。

Apart from test suites, we can also create test groups in TestNG, where instead of test classes methods are grouped together. In order to do that, add the groups parameter in the @Test annotation:

除了测试套件,我们还可以在TestNG中创建测试组,将测试类的方法归为一组。为了做到这一点,在@Test注释中添加groups参数。

@Test(groups = "regression")
public void givenNegativeNumber_sumLessthanZero_thenCorrect() {
    int sum = numbers.stream().reduce(0, Integer::sum);
 
    assertTrue(sum < 0);
}

Let’s use an XML to execute the groups:

让我们用一个XML来执行组。

<test name="test groups">
    <groups>
        <run>
            <include name="regression" />
        </run>
    </groups>
    <classes>
        <class
          name="com.baeldung.SummationServiceTest" />
    </classes>
</test>

This will execute the test method tagged with group regression, in the SummationServiceTest class.

这将执行SummationServiceTest类中标记为regression, 组的测试方法。

7. Parameterized Tests

7.参数化测试

Parameterized unit tests are used for testing the same code under several conditions. With the help of parameterized unit tests, we can set up a test method that obtains data from some data source. The main idea is to make the unit test method reusable and to test with a different set of inputs.

参数化单元测试用于在多个条件下测试同一代码。在参数化单元测试的帮助下,我们可以设置一个测试方法,从一些数据源获取数据。其主要思想是使单元测试方法可重复使用,并以不同的输入集进行测试。

In TestNG, we can parametrize tests using @Parameter or @DataProvider annotation. While using the XML file annotate the test method with @Parameter:

在TestNG中,我们可以使用@Parameter@DataProvider注解对测试进行参数化。在使用XML文件时,用@Parameter:注解测试方法。

@Test
@Parameters({"value", "isEven"})
public void
  givenNumberFromXML_ifEvenCheckOK_thenCorrect(int value, boolean isEven) {
    
    assertEquals(isEven, value % 2 == 0);
}
And provide the data using XML file:
<suite name="My test suite">
    <test name="numbersXML">
        <parameter name="value" value="1"/>
        <parameter name="isEven" value="false"/>
        <classes>
            <class name="baeldung.com.ParametrizedTests"/>
        </classes>
    </test>
</suite>

Using data from XML file is useful, but we often need more complex data. @DataProvider annotation is used to handle these scenarios, which can be used to map complex parameter types for testing methods.@DataProvider for primitive data types:

使用来自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);
}

@DataProviderfor objects:

@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)}};
}

Using this, any object that has to be tested can be created and used in the test. This is mostly useful for integration test cases.

使用它,任何需要测试的对象都可以在测试中创建和使用。这对集成测试案例来说非常有用。

8. Ignoring Test Cases

8.忽视测试用例

We sometimes want not to execute a certain test case, temporarily during the development process. This can be done adding enabled=false, in the @Test annotation:

我们有时希望在开发过程中暂时不执行某个测试案例。这可以在@Test 注解中添加enabled=false,来实现。

@Test(enabled=false)
public void givenNumbers_sumEquals_thenCorrect() { 
    int sum = numbers.stream.reduce(0, Integer::sum);
    assertEquals(6, sum);
}

9. Dependent Tests

9.从属测试

Let’s consider a scenario, where if the initial test case fails, all subsequent test cases should be executed, and rather be marked as skipped. TestNG provides this feature with the dependsOnMethods parameter of the @Test annotation:

让我们考虑一个场景,如果初始测试用例失败,所有后续测试用例都应该被执行,而不是被标记为跳过。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);
}

Notice that, the login test case depends on the email validation test case. Thus, if email validation fails the login test will be skipped.

注意,登录测试案例依赖于电子邮件验证测试案例。因此,如果电子邮件验证失败,登录测试将被跳过。

10. Concurrent Test Execution

10.并行测试执行

TestNG allows tests to run in parallel or in multi-threaded mode, thus providing a way to test these multi-threaded pieces of code.

TestNG允许测试在并行或多线程模式下运行,从而提供了一种测试这些多线程代码的方法。

You can configure, for methods, classes, and suites to run in their own threads reducing the total execution time.

你可以配置,让方法、类和套件在自己的线程中运行,以减少总的执行时间。

10.1. Classes and Methods in Parallel

10.1.并行的类和方法

To run test classes in parallel, mention the parallel attribute in the suite tag in XML configuration file, with value classes:

要并行运行测试类,在XML配置文件的suite标签中提到parallel属性,其值为classes:

<suite name="suite" parallel="classes" thread-count="2">
    <test name="test suite">
        <classes>
	    <class name="baeldung.com.RegistrationTest" />
            <class name="baeldung.com.SignInTest" />
        </classes>
    </test>
</suite>

Note that, if we have multiple test tags in the XML file, these tests can also be run in parallel, by mentioning parallel =” tests”. Also to execute individual methods in parallel, mention parallel =” methods”.

请注意,如果我们在XML文件中有多个test tag,这些测试也可以并行运行,只要提到parallel =” tests”。同样,如果要并行执行单个方法,请提及parallel =” methods”.

10.2. Multi-Threaded Execution of Test Method

10.2.测试方法的多线程执行

Let’s say we need to test the behavior of a code when running in multiple threads. TestNG allows to run a test method in multiple threads:

比方说,我们需要测试一个代码在多线程中运行时的行为。TestNG允许在多线程中运行一个测试方法。

public class MultiThreadedTests {
    
    @Test(threadPoolSize = 5, invocationCount = 10, timeOut = 1000)
    public void givenMethod_whenRunInThreads_thenCorrect() {
        int count = Thread.activeCount();
 
        assertTrue(count > 1);
    }
}

The threadPoolSize indicates that the method will run in n number of threads as mentioned. The invocationCount and timeOut indicate that the test will be executed multiple times and fail the test if it takes more time.

threadPoolSize表示该方法将在n所述的线程数中运行。invocationCounttimeOut表示测试将被多次执行,如果花费更多时间,则测试失败。

11. Functional Testing

11.功能测试

TestNG comes with features which can be used for functional testing as well. In conjunction with Selenium, it can either be used to test functionalities of a web application or used for testing web services with HttpClient.

TestNG具有的功能也可用于功能测试。与Selenium结合使用,它既可用于测试Web应用程序的功能,也可用于测试带有HttpClient的Web服务。

More details about functional testing with Selenium and TestNG is available here. Also some more pieces of stuff on integration testing in this article.

关于使用Selenium和TestNG进行功能测试的更多细节可在这里。在这篇文章中还有一些关于集成测试的内容

12. Conclusion

12.结语

In this article, we had a quick look at how to setup TestNG and execute a simple test case, generate reports, concurrent execution of test cases and also a little about functional programming. For more features like dependent tests, ignoring test cases, test groups and suites you can refer our JUnit vs TestNG article here.

在这篇文章中,我们快速了解了如何设置TestNG并执行一个简单的测试用例,生成报告,测试用例的并发执行,以及关于函数式编程的一些情况。关于更多的功能,如依赖测试、忽略测试用例、测试组和套件,你可以参考我们的JUnit vs TestNG文章这里

The implementation of all the code snippets can be found over on Github.

所有代码片断的实现都可以在Github上找到over