Java Unit Testing JUnit 5 Quick Start

Foreword

Unit testing is essential for software development in a ring, but often because the project cycle tight, heavy workload and is choosing to ignore the common development, which often lead to software issues abound. In fact, many problems arise online can be timely detection and treatment in case there is unit testing, and therefore cultivate their ability to write unit tests in the daily development is necessary. Whether it is to improve their coding ability, or quality improvement project, will greatly benefit, this article will introduce Java unit testing framework JUnit basic understanding and use 5 to write unit tests, we want the same for your help.

All involved in this paper are in the following code snippet repository, interested in learning junior partner welcome reference:

https://github.com/wrcj12138aaa/junit5-actions

Supported in:

  • JDK 8
  • JUnit 5.5.2
  • Lomo 1.18.8

Understanding JUnit 5

To say what is JUnit 5, we must first talk at Java unit testing framework JUnit, TestNG framework it with another occupied the main market areas in Java unit testing framework, JUnit which has a long history of development and evolving feature-rich , much favored by the majority of Java developers.

Talking about the history of JUnit, JUnit originated in 1997, the original version is completed by two of the master programmer Kent Beck and Erich Gamma's first airplane trip, because of the lack of sophisticated tools Java testing process, the two aircraft on cooperation on the design and implementation of JUnit prototype, designed to be easier to use the Java testing framework. Today, twenty years later, JUnit through various versions of iterative evolution, has been developed to version 5.x, provide better support for the JDK version 8 and higher (such as support for Lambda) and a richer form of testing (such as repeat test, parametric test).

Knowing too JUint, then come back and look at JUnit 5, can be said that this version is a major upgrade JUnit unit test framework, we first need Java more than 8 operating environment, although it can compile an older version JDK to run, but to fully use JUnit 5 features, JDK 8 environment is essential.

In addition, versions of JUnit JUnit. 5 and different from before, split into several different sub modules of three different compositions.

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

  • Platform JUnit : Start the JVM for basic services testing framework provides the command line, IDE and build support for testing tools and other means.

  • Jupiter JUnit : JUnit 5 includes a new programming model and expansion model, is mainly used to write test code and spreading code.

  • Vintage JUnit : a test case JUnit3.x and JUnit4.x of JUnit 5 in compatible operation.

Based on the above description, illustrated in Figure 17 an understanding of the structure and JUnit module 5:

Why JUnit 5

After 5 JUnit What is finished, let us think of a question: Why do we need a JUnit 5 it?

Ever since a similar test frameworks like JUnit, Java unit testing field matures, the developer unit testing framework also have higher requirements: to rely on other libraries more testing way less. Therefore, we look forward to a more powerful test frameworks birth, JUnit Java test as a leader in the field, the introduction of JUnit 5 this version, the main features:

  • Provide a new test assertions and notes, support for embedded test class
  • Richer test: support dynamic testing, repeat testing, parametric testing
  • Achieve a modular, so different modules decoupling test execution and test discovery, reduce dependence

  • 8 provides support for Java, such as Lambda expressions, Sream API and so on.

JUnit 5 common usage presentation

Next, we look at some of the common uses JUni 5, and to help us to quickly master the use of JUnit 5.

First, the introduction of dependent coordinates Maven JUnit 5 in the project, it must be noted that the current environment to be in Java 8 JDK above.

<dependency>
  <groupId>org.junit.jupiter</groupId>
  <artifactId>junit-jupiter-engine</artifactId>
  <version>5.5.2</version>
  <scope>test</scope>
</dependency>

The first test case

The introduction of JUnit 5, we can start to quickly write a simple test case from this preliminary test to know under JUnit 5:

@DisplayName("我的第一个测试用例")
public class MyFirstTestCaseTest {

    @BeforeAll
    public static void init() {
        System.out.println("初始化数据");
    }

    @AfterAll
    public static void cleanup() {
        System.out.println("清理数据");
    }

    @BeforeEach
    public void tearup() {
        System.out.println("当前测试方法开始");
    }

    @AfterEach
    public void tearDown() {
        System.out.println("当前测试方法结束");
    }

    @DisplayName("我的第一个测试")
    @Test
    void testFirstTest() {
        System.out.println("我的第一个测试开始测试");
    }

    @DisplayName("我的第二个测试")
    @Test
    void testSecondTest() {
        System.out.println("我的第二个测试开始测试");
    }
}

Direct run this test, you can see the console log is as follows:

The results can be seen on the left column of test items in the display name is what we use in the test classes and methods @DisplayName name set, this comment is the introduction of JUnit 5, used to define a test class and specify the use cases to show in the test report name, you can use this annotation on the class and the methods used on the class it represents the class as a test class, using the method indicates that the method for testing methods.

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@API(status = STABLE, since = "5.0")
public @interface DisplayName {
    String value();
}

Then look at the code used to sample a pair of annotations @BeforeAll and @AfterAll , and they define at the end of the operation before the start of the entire test class, modified only static methods, mainly used in the overall testing process required initialization and cleanup data and external resources. And they are different, @BeforeEach and @AfterEach method marked and will be executed at the end before the beginning of each test method is mainly responsible for preparing and destruction of the test cases required operating environment.

During the test, in addition to these basic notes, annotations and more rich and powerful, next to us one learn under the bar.

Disable perform the test: @Disabled

When we want to run the test in the class, skip a test method, when the normal operation of other test cases, we can spend @Disabled annotation indicates that the test method can not be used, the test method will not perform the test class is JUnit execution.

The following operation effect using look after @Disbaled, add the following code in the original test class:

@DisplayName("我的第三个测试")
@Disabled
@Test
void testThirdTest() {
    System.out.println("我的第三个测试开始测试");
}

After running to see the console log is as follows, with @Disabled marking method will not be executed, only a single method Print:

@Disabled class may also be used on, for all test methods are not performed under the tag class, the test is generally used when a plurality of classes of combinations tested.

Embedded test class: @Nested

When we write classes and code gradually increased, followed by a corresponding test class to be tested will be more and more. In order to solve the problem of the number of class test explosion, JUnit 5 provides @Nested notes, test cases can be logically grouped in the form of a static internal class members of the class. And each static inner classes can have their own lifecycle methods that will be executed from the outside in hierarchical order. In addition, nested classes can also be used @DisplayName mark, so that we can correct the test name. The following look simple usage:

@DisplayName("内嵌测试类")
public class NestUnitTest {
    @BeforeEach
    void init() {
        System.out.println("测试方法执行前准备");
    }

    @Nested
    @DisplayName("第一个内嵌测试类")
    class FirstNestTest {
        @Test
        void test() {
            System.out.println("第一个内嵌测试类执行测试");
        }
    }

    @Nested
    @DisplayName("第二个内嵌测试类")
    class SecondNestTest {
        @Test
        void test() {
            System.out.println("第二个内嵌测试类执行测试");
        }
    }
}

After running all the test cases in the console to see the following results:

Repeatability test: @RepeatedTest

In JUnit 5 set to run in a number of new test methods support, allowing to make the test method is run repeatedly. When a test method to be run N times, it may be used @RepeatedTest mark, as shown in the following code:

@DisplayName("重复测试")
@RepeatedTest(value = 3)
public void i_am_a_repeated_test() {
    System.out.println("执行测试");
}

After running the test method is executed three times, the operation effect IDEA as shown below:

This is the basic usage, we can modify the test method names run repeatedly, using the built-in variable @RepeatedTest provided thereon a placeholder manner nameusing the property, use and look under the following effects:

@DisplayName("自定义名称重复测试")
@RepeatedTest(value = 3, name = "{displayName} 第 {currentRepetition} 次")
public void i_am_a_repeated_test_2() {
    System.out.println("执行测试");
}

@RepeatedTest notes within a currentRepetitionvariable represents the number of times has been repeated, totalRepetitionsvariable represents the total number of times to repeat, displayNamevariable represents the display name of the test method, we can directly use these built-in variables to redefine the name of the test method is repeated runtime.

New assertions

On the assertion API design, JUnit 5 were significantly improved, and take advantage of new features in Java 8, in particular, Lambda expressions, and ultimately provide a new class of assertions: org.junit.jupiter.api.Assertions . Many accept the assertion methods Lambda expressions parameters, using the advantages of a Lambda expression in the assertion that it is the message of delay calculation, great news if construction costs, this can save time and resources to some extent.

Now more assertions may also be grouped in one method, a method using assertAll following sample code:

@Test
void testGroupAssertions() {
    int[] numbers = {0, 1, 2, 3, 4};
    Assertions.assertAll("numbers",
            () -> Assertions.assertEquals(numbers[1], 1),
            () -> Assertions.assertEquals(numbers[3], 3),
            () -> Assertions.assertEquals(numbers[4], 4)
    );
}

If any assertion of a failed packet assertion will throw errors will MultipleFailuresError prompt.

Test timeout operation: assertTimeoutPreemptively

When we want to perform time consuming testing methods, testing methods did not want to wait indefinitely, you can test a timeout test method, JUnit 5 launched this assertion methods assertTimeout, provides extensive support for the timeout.

Suppose we want to test code is completed within one second, you can write test cases as follows:

@Test
@DisplayName("超时方法测试")
void test_should_complete_in_one_second() {
  Assertions.assertTimeoutPreemptively(Duration.of(1, ChronoUnit.SECONDS), () -> Thread.sleep(2000));
}

The test fails, because the code execution will sleep two seconds, and we look forward to a successful test in less than a second. But if we set up a second time to sleep, there will still be a test case of the occasional failure, because during the execution of the test method in addition to the object code as well as additional code and instruction execution will be time-consuming, so I can not do on the timeout limit exact match to the complete time parameter.

Abnormal test: assertThrows

We code for the method usually used with anomaly try-catch capture processing mode, with the code for the test so that the exception is thrown, and JUnit 5 provides a method Assertions#assertThrows(Class<T>, Executable)for testing, the first parameter is an abnormal type, a second as a function of a parameter interface, the interface is similar with the Runnable, no parameters and returns no, and the way to use supports Lambda expressions, refer to the specific use code below:

@Test
@DisplayName("测试捕获的异常")
void assertThrowsException() {
  String str = null;
  Assertions.assertThrows(IllegalArgumentException.class, () -> {
    Integer.valueOf(str);
  });
}

When Lambda expressions in the code that appears abnormal is compared with the first parameter of the exception type, if you do not belong to the same class of exceptions, console output will be similar to the following tips:org.opentest4j.AssertionFailedError: Unexpected exception type thrown ==> expected: <IllegalArgumentException> but was: <...Exception>

JUnit 5 parametric test

To test parameterized JUnit 5, except junit-jupiter-engine-dependent basis, but also dependent on other modules: JUnit-Jupiter-the params , which mainly provides a parametric test write API. In the same manner, corresponding to the same version introduced dependence Maven Engineering:

<dependency>
  <groupId>org.junit.jupiter</groupId>
  <artifactId>junit-jupiter-params</artifactId>
  <version>5.5.2</version>
  <scope>test</scope>
</dependency>

Basic Data Source Test: @ValueSource

@ValueSource parameter is the simplest data source JUnit 5 provided, eight support Java primitive types and strings, Class, corresponding to the type of the attributes assigned to the use of annotations, passing as an array, the following sample code:

public class ParameterizedUnitTest {
    @ParameterizedTest
    @ValueSource(ints = {2, 4, 8})
    void testNumberShouldBeEven(int num) {
        Assertions.assertEquals(0, num % 2);
    }

    @ParameterizedTest
    @ValueSource(strings = {"Effective Java", "Code Complete", "Clean Code"})
    void testPrintTitle(String title) {
        System.out.println(title);
    }
}

@ParameterizedTest notes as necessary parametric tests, replacing the @Test comment. Any parameterized test methods require markings on the Notes.

Run the test, the results shown below, for @ValueSource in each parameter runs the target method, which once operational parameters of the test fails, it means that the test method is not passed.

CSV Data Source Test: @CsvSource

@CsvSource can be injected through a set of data specified CSV format (comma-separated-values), and a comma-separated values ​​for each parameter to match a corresponding test method, using the following example:

@ParameterizedTest
@CsvSource({"1,One", "2,Two", "3,Three"})
void testDataFromCsv(long id, String name) {
    System.out.printf("id: %d, name: %s", id, name);
}

The results shown in FIG run, separated by a comma in addition to the outer, @ CsvSource also supports custom symbols, as long as it is modified delimiterto, by default .

JUnit also provides read external data files CSV format as a way to achieve a data source, as long as we use @CsvFileSource specify the path to the resource file, as easy to use with @CsvSource will not repeat here demonstrates.

When @CsvFileSource specified resource file path To /begin, find the file in the current directory test resources.

In addition to the three data sources of the above-mentioned manner, JUnit also provides three data sources:

  • @EnumSource : allows us to pass parameter values to specify the type of incoming Enum enumeration, enumeration type constructed in a specific value.
  • @MethodSource : Specifies a return Stream / Array / iterative approach may be subjected to the data source. Note that this method must be static, and can not accept any parameters.
  • @ArgumentSource : ArgumentsProvider parameter class by implementing an interface for the data source, which override the provideArgumentsmethod may return a custom type Stream <Arguments>, is used as the data required for the test method.

Annotation data source for the above three interested students can refer to ParameterizedUnitTest class example project, there is not a has repeatedly introduced.

Epilogue

Here, surely you also have to JUnit 5 basic understanding and knowledge of, say unit test software is to enhance the quality, improve the efficiency of research and development necessary links will start with from 5 to write JUnit unit test, develop the habit of writing test code, improve their development efficiency continues to practice, let's write code that has more quality assurance.

Recommended Reading

Reference material

  • https://junit.org/junit5/docs/current/user-guide/#overview-getting-started-junit-artifacts

  • https://www.baeldung.com/junit-5

  • https://zhuanlan.zhihu.com/p/43902194
  • https://dev.to/stealthmusic/why-you-should-start-using-junit-5-5gk2
  • 《Java Unit Testing with JUnit 5》

Guess you like

Origin www.cnblogs.com/one12138/p/11536492.html
Recommended