Introduction to JUnitParams – JUnitParams简介

最后修改: 2017年 5月 29日

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

1. Overview

1.概述

In this article, we’ll explore the JUnitParams library and its usages. Simply put, this library provides easy parameterization of test methods in JUnit tests.

在这篇文章中,我们将探讨JUnitParams库及其使用方法。简单地说,这个库为JUnit测试中的测试方法提供了简单的参数化。

There are situations where the only thing that changes between multiple tests are the parameters. JUnit itself has a parameterization support, and JUnitParams significantly improves on that functionality.

有些情况下,多个测试之间唯一变化的是参数。JUnit本身就有参数化支持,而JUnitParams则极大地改进了这一功能。

2. Maven Dependency

2.Maven的依赖性

To use JUnitParams in our project, we need to add it to our pom.xml:

为了在我们的项目中使用 JUnitParams,我们需要将其添加到我们的pom.xml

<dependency>
    <groupId>pl.pragmatists</groupId>
    <artifactId>JUnitParams</artifactId>
    <version>1.1.0</version>
</dependency>

The latest version of the library can be found here.

该库的最新版本可以在这里找到。

3. Test Scenario

3.测试场景

Let’s create a class which does the safe addition of two integers. This should return Integer.MAX_VALUE if it overflows, and Integer.MIN_VALUE if it underflows:

让我们创建一个类,对两个整数进行安全加法。如果溢出,它应该返回Integer.MAX_VALUE;如果溢出,则返回Integer.MIN_VALUE

public class SafeAdditionUtil {

    public int safeAdd(int a, int b) {
        long result = ((long) a) + b;
        if (result > Integer.MAX_VALUE) {
            return Integer.MAX_VALUE;
        } else if (result < Integer.MIN_VALUE) {
            return Integer.MIN_VALUE;
        }
        return (int) result;
    }
}

4. Constructing a Simple Test Method

4.构建一个简单的测试方法

We’ll need to test method implementation for different combinations of input values, to make sure the implementation holds true for all possible scenarios. JUnitParams provides more than one way to achieve the parameterized test creation.

我们需要针对不同的输入值组合测试方法的实现,以确保实现在所有可能的情况下都成立。JUnitParams提供了不止一种方法来实现参数化测试的创建。

Let’s take the basic approach with a minimal amount of coding and see how it is done. After that, we can see what the other possible ways of implementing the test scenarios using JUnitParams are:

让我们采取基本的方法,用最少的编码,看看它是如何完成的。之后,我们可以看看使用JUnitParams实现测试场景的其他可能方式是什么

@RunWith(JUnitParamsRunner.class)
public class SafeAdditionUtilTest {

    private SafeAdditionUtil serviceUnderTest
      = new SafeAdditionUtil();

    @Test
    @Parameters({ 
      "1, 2, 3", 
      "-10, 30, 20", 
      "15, -5, 10", 
      "-5, -10, -15" })
    public void whenWithAnnotationProvidedParams_thenSafeAdd(
      int a, int b, int expectedValue) {
 
        assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b));
    }

}

Now let’s see how this test class differs from a regular JUnit test class.

现在让我们看看这个测试类与普通的JUnit测试类有什么不同。

The first thing we notice is that there is a different test runner in the class annotation – JUnitParamsRunner.

我们首先注意到有一个不同的测试运行器的类注释–JUnitParamsRunner

Moving on to the test method, we see the test method is annotated with @Parameters annotation with an array of input parameters. It indicates different test scenarios which will be used for testing our service method.

继续看测试方法,我们看到测试方法被@Parameters注解,有一个输入参数的数组。它指出了不同的测试场景,这些场景将被用于测试我们的服务方法。

If we run the test using Maven, we’ll see that we are running four test cases and not a single one. The output would be similar to the following:

如果我们用Maven运行该测试,我们会发现我们正在运行四个测试用例,而不是一个。输出结果将类似于以下内容。

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.baeldung.junitparams.SafeAdditionUtilTest
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.068 sec 
  - in com.baeldung.junitparams.SafeAdditionUtilTest

Results :

Tests run: 4, Failures: 0, Errors: 0, Skipped: 0

5. Different Types of Parameterization of Test Methods

5.测试方法参数化的不同类型

Providing test parameters directly in the annotation is certainly not the most readable way if we have lots of possible scenarios that need to be tested. JUnitParams offers a set of different approaches we can utilize to create the parameterized tests:

如果我们有很多需要测试的可能场景,直接在注释中提供测试参数肯定不是最易读的方式。JUnitParams提供了一套不同的方法,我们可以利用它来创建参数化测试。

  • Directly in the @Parameters annotation (used in the example above)
  • Using a named test method defined within the annotation
  • Using a method mapped by test method name
  • A named test class defined within the annotation
  • Using a CSV file

Let’s explore the approaches one by one.

让我们逐一探讨这些方法。

5.1. Directly in the @Parameters Annotation

5.1.直接在@Parameters注释中进行

We have already used this approach in the example we tried. What we need to keep in mind is that we should be providing an array of parameter strings. Within the parameter string, each parameter is separated by a comma.

在我们尝试的例子中,我们已经使用了这种方法。我们需要记住的是,我们应该提供一个参数字符串的数组。在参数字符串中,每个参数都用逗号分开。

For example, the array would be in the form of { “1, 2, 3”, “-10, 30, 20”} and one set of parameters is represented as “1, 2, 3”.

例如,数组的形式为{“1,2,3″,”-10,30,20″},一组参数表示为“1,2,3”

The limitation of this approach is that we can only supply primitives and Strings as test parameters. It is not possible to submit objects as test method parameters as well.

这种方法的限制是,我们只能提供基元和Strings作为测试参数。不可能同时提交对象作为测试方法参数。

5.2. Parameter Method

5.2.参数方法

We can provide the test method parameters using another method within the class. Let’s see an example first:

我们可以使用类中的另一个方法来提供测试方法的参数。让我们先看一个例子。

@Test
@Parameters(method = "parametersToTestAdd")
public void whenWithNamedMethod_thenSafeAdd(
  int a, int b, int expectedValue) {
 
    assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b));
}

private Object[] parametersToTestAdd() {
    return new Object[] { 
        new Object[] { 1, 2, 3 }, 
        new Object[] { -10, 30, 20 }, 
        new Object[] { Integer.MAX_VALUE, 2, Integer.MAX_VALUE }, 
        new Object[] { Integer.MIN_VALUE, -8, Integer.MIN_VALUE } 
    };
}

The test method is annotated concerning the method parametersToAdd(), and it fetches the parameters by running the referenced method.

测试方法被注解为与方法parametersToAdd()有关,并且它通过运行引用的方法来获取参数。

The specification of the provider method should return an array of Objects as a result. If a method with the given name is not available, the test case fails with the error:

提供者方法的规范应该返回一个Objects数组作为结果。如果一个具有给定名称的方法不可用,测试案例就会失败,出现错误。

java.lang.RuntimeException: Could not find method: bogusMethodName so no params were used.

5.3. Method Mapped by Test Method Name

5.3.按测试方法名称映射的方法

If we do not specify anything in the @Parameters annotation, JUnitParams tries to load a test data provider method based on the test method name. The method name is constructed as “parametersFor”+ <test method name>:

如果我们没有在@Parameters注解中指定任何东西,JUnitParams会尝试根据测试方法名称加载一个测试数据提供者方法。该方法名称被构造为“parametersFor “+<测试方法名称>:

@Test
@Parameters
public void whenWithnoParam_thenLoadByNameSafeAdd(
  int a, int b, int expectedValue) {
 
    assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b));
}

private Object[] parametersForWhenWithnoParam_thenLoadByNameSafe() {
    return new Object[] { 
        new Object[] { 1, 2, 3 }, 
        new Object[] { -10, 30, 20 }, 
        new Object[] { Integer.MAX_VALUE, 2, Integer.MAX_VALUE }, 
        new Object[] { Integer.MIN_VALUE, -8, Integer.MIN_VALUE } 
    };
}

In the above example the name of the test method is whenWithnoParam_shouldLoadByNameAbdSafeAdd().

在上面的例子中,测试方法的名称是whenWithnoParam_shouldLoadByNameAbdSafeAdd()

Therefore when the test method is being executed, it looks for a data provider method with the name parametersForWhenWithnoParam_shouldLoadByNameAbdSafeAdd().

因此,当测试方法被执行时,它寻找一个名字为parametersForWhenWithnoParam_shouldLoadByNameAbdSafeAdd()的数据提供者方法。

Since that method exists, it will load data from it and run the test. If there is no such method matching the required name, the test fails as in the above example.

由于该方法存在,它将从其中加载数据并运行测试。如果没有与所需名称相匹配的方法,测试就会失败,如上面的例子。

5.4. Named Test Class Defined Within the Annotation

5.4.在注释中定义的命名测试类

Similar to the way we referred to a data provider method in a previous example, we can refer to a separate class to provide the data for our test:

类似于我们在前面的例子中提到的数据提供方法,我们可以引用一个单独的类来为我们的测试提供数据。

@Test
@Parameters(source = TestDataProvider.class)
public void whenWithNamedClass_thenSafeAdd(
  int a, int b, int expectedValue) {
 
    assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b));
}
public class TestDataProvider {

    public static Object[] provideBasicData() {
        return new Object[] { 
            new Object[] { 1, 2, 3 }, 
            new Object[] { -10, 30, 20 }, 
            new Object[] { 15, -5, 10 }, 
            new Object[] { -5, -10, -15 } 
        };
    }

    public static Object[] provideEdgeCaseData() {
        return new Object[] { 
            new Object[] { 
              Integer.MAX_VALUE, 2, Integer.MAX_VALUE }, 
            new Object[] { 
              Integer.MIN_VALUE, -2, Integer.MIN_VALUE }, 
        };
    }
}

We can have any number of test data providers in a class given that the method name starts with “provide”. If so, the executor picks those methods and returns the data.

鉴于方法名称以 “provide “开头,我们可以在一个类中拥有任意数量的测试数据提供者。如果是这样,执行器就会选择这些方法并返回数据。

If no class methods are satisfying that requirement, even though those methods return an array of Objects, those methods will be ignored.

如果没有类的方法满足这一要求,即使这些方法返回一个Objects的数组,这些方法将被忽略。

5.5. Using a CSV File

5.5.使用CSV文件

We can use an external CSV file to load the test data. This helps if the number of possible test cases is quite significant, or if test cases are frequently changed. The changes can be done without affecting the test code.

我们可以使用一个外部CSV文件来加载测试数据。如果可能的测试用例的数量相当大,或者测试用例经常被改变,这就有帮助。这些变化可以在不影响测试代码的情况下进行。

Let’s say that we have a CSV file with test parameters as JunitParamsTestParameters.csv:

假设我们有一个包含测试参数的CSV文件为 JunitParamsTestParameters.csv

1,2,3
-10, 30, 20
15, -5, 10
-5, -10, -15

Now let’s look how this file can be used to load test parameters in the test method:

现在让我们看看这个文件如何用于在测试方法中加载测试参数

@Test
@FileParameters("src/test/resources/JunitParamsTestParameters.csv")
public void whenWithCsvFile_thenSafeAdd(
  int a, int b, int expectedValue) {
 
    assertEquals(expectedValue, serviceUnderTest.safeAdd(a, b));
}

One limitation of this approach is that it is not possible to pass complex objects. Only primitives and Strings are valid.

这种方法的一个限制是不可能传递复杂的对象。只有基元和Strings是有效的。

6. Conclusion

6.结论

In this tutorial, we looked at how can we can utilize the functionalities of JUnitParams in a nutshell.

在本教程中,我们看了如何能够利用JUnitParams的功能,简而言之。

We also covered different approaches the library provides us to supply test parameters to our test methods – well beyond what JUnit itself can do.

我们还涵盖了该库为我们提供的为测试方法提供测试参数的不同方法–远远超出了JUnit本身所能做到的。

As always, the source code can be found over on GitHub.

一如既往,源代码可以在GitHub上找到over