JUnit5教程

时间:2020-02-23 14:35:25  来源:igfitidea点击:

在本Junit教程中,我们将通过示例介绍JUnit5的基础知识及其新功能。
在Java世界中,JUnit是用于对Java代码实施单元测试的流行框架之一。
JUnit主要帮助开发人员自己在JVM上测试其代码。

JUnit5架构

JUnit平台

  • 在JVM上启动测试框架
  • 使用TestEngine API来构建在JUnit平台上运行的测试框架

JUnit木星

  • 混合了用于编写测试的新编程模型和用于扩展的扩展模型
  • 添加了新的注释,例如@ BeforeEach,@ AfterEach,@ AfterAll,@ BeforeAll等。

JUnit复古

  • 提供支持以在此新平台上执行以前的JUnit版本3和4测试

JUnit Maven依赖关系

要在项目中实现基于JUnit5的测试用例,请将以下依赖项添加到项目的pom.xml文件中:

  • JUnit 5库
<dependency>
   <groupId>org.junit.jupiter</groupId>
   <artifactId>junit-jupiter-engine</artifactId>
   <version>5.1.1</version>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>org.junit.platform</groupId>
   <artifactId>junit-platform-runner</artifactId>
   <version> 1.1.1</version>
   <scope>test</scope>
</dependency>
  • JUnit5 maven surefire提供程序在IDE不支持JUnit5的情况下执行单元测试(如果IDE支持,则不需要这一点)
<plugin>
   <artifactId>maven-surefire-plugin</artifactId>
   <version>2.19.1</version>
   <dependencies>
        <dependency>
             <groupId>org.junit.platform</groupId>
             <artifactId>junit-platform-surefire-provider</artifactId>
             <version>1.0.2</version>
        </dependency>
   </dependencies>
</plugin>

JUnit5的新功能

运行时需要Java 8或者更高版本。
但是仍然可以测试使用以前的Java版本编译的代码。
其中引入了各种新功能。

JUnit注释

下面列出了其中提供的一些常用注释:

@TestDenotes a test method
@DisplayNameDeclares a custom display name for the test class or test method
@BeforeEachDenotes that the annotated method should be executed before each test method
@AfterEachDenotes that the annotated method should be executed after each test method
@BeforeAllDenotes that the annotated method should be executed before all test methods
@AfterAllDenotes that the annotated method should be executed after all test methods
@DisableUsed to disable a test class or test method
@NestedDenotes that the annotated class is a nested, non-static test class
@TagDeclare tags for filtering tests
@ExtendWithRegister custom extensions
package com.theitroad;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

public class JUnit5Sample1Test {

@BeforeAll
static void beforeAll() {
  System.out.println("**--- Executed once before all test methods in this class ---**");
}

@BeforeEach
void beforeEach() {
  System.out.println("**--- Executed before each test method in this class ---**");
}

@Test
void testMethod1() {
  System.out.println("**--- Test method1 executed ---**");
}

@DisplayName("Test method2 with condition")
@Test
void testMethod2() {
  System.out.println("**--- Test method2 executed ---**");
}

@Test
@Disabled("implementation pending")
void testMethod3() {
	  System.out.println("**--- Test method3 executed ---**");
}

@AfterEach
void afterEach() {
  System.out.println("**--- Executed after each test method in this class ---**");
}

@AfterAll
static void afterAll() {
  System.out.println("**--- Executed once after all test methods in this class ---**");
}

}

我们可以在Eclipse-> Run As-> JUnit Test中的JUnit测试类之上运行。

JUnit断言

必须使用断言将每个测试方法的条件评估为true,以便测试可以继续执行。
JUnit Jupiter断言保存在org.junit.jupiter.api.Assertions类中。
所有方法都是静态的。

assertEquals(expected, actual)Fails when expected does not equal actual
assertFalse(expression)Fails when expression is not false
assertNull(actual)Fails when actual is not null
assertNotNull(actual)Fails when actual is null
assertAll()Group many assertions and every assertion is executed even if one or more of them fails
assertTrue(expression)Fails if expression is not true
assertThrows()Class to be tested is expected to throw an exception
@Test
void testAssertEqual() {
	 assertEquals("ABC", "ABC");
	 assertEquals(20, 20, "optional assertion message");
	 assertEquals(2 + 2, 4);
}

@Test
void testAssertFalse() {
	 assertFalse("FirstName".length() == 10);
	 assertFalse(10 > 20, "assertion message");
}

@Test
void testAssertNull() {
   String str1 = null;
	 String str2 = "abc";
	 assertNull(str1);
	 assertNotNull(str2);	
}

@Test
void testAssertAll() {
	 String str1 = "abc";
	 String str2 = "pqr";
	 String str3 = "xyz";
	 assertAll("numbers",
	      () -> assertEquals(str1,"abc"),
		  () -> assertEquals(str2,"pqr"),
		  () -> assertEquals(str3,"xyz")
	 );
	 //uncomment below code and understand each assert execution
   /*assertAll("numbers",
		  () -> assertEquals(str1,"abc"),
		  () -> assertEquals(str2,"pqr1"),
		  () -> assertEquals(str3,"xyz1")
	 );*/
}

@Test
void testAssertTrue() {
	 assertTrue("FirstName".startsWith("F"));
	 assertTrue(10  {
	      throw new IllegalArgumentException("Illegal Argument Exception occured");
	 });
	 assertEquals("Illegal Argument Exception occured", exception.getMessage());
}

JUnit5导入

它的测试类需要" org.junit.jupiter.api.Test"导入语句,而不是" org.junit.Test"。
同样,测试方法不必是公共和本地程序包。

import org.junit.jupiter.api.Test;

JUnit5假设

假设是org.junit.jupiter.api.Assumptions类中的静态方法。
他们仅在满足指定条件时执行测试,否则测试将中止。
中止的测试不会导致构建失败。
如果假设失败,则抛出org.opentest4j.TestAbortedException,并且跳过测试。

assumeTrueExecute the body of lamda when the positive condition hold else test will be skipped
assumeFalseExecute the body of lamda when the negative condition hold else test will be skipped
assumingThatPortion of the test method will execute if an assumption holds true and everything after the lambda will execute irrespective of the assumption in assumingThat() holds
@Test
void testAssumeTrue() {
   boolean b = 'A' == 'A';
   assumeTrue(b);
   assertEquals("Hello", "Hello");
}

@Test
@DisplayName("test executes only on Saturday")
public void testAssumeTrueSaturday() {
   LocalDateTime dt = LocalDateTime.now();
   assumeTrue(dt.getDayOfWeek().getValue() == 6);
   System.out.println("further code will execute only if above assumption holds true");
}

@Test
void testAssumeFalse() {
   boolean b = 'A' != 'A';
   assumeFalse(b);
   assertEquals("Hello", "Hello");
}

@Test
void testAssumeFalseEnvProp() {
   System.setProperty("env", "prod");
   assumeFalse("dev".equals(System.getProperty("env")));
   System.out.println("further code will execute only if above assumption hold");
}

@Test
void testAssumingThat() {
   System.setProperty("env", "test");
   assumingThat("test".equals(System.getProperty("env")),
        () -> {
             assertEquals(10, 10);
             System.out.println("perform below assertions only on the test env");
             });

   assertEquals(20, 20);
   System.out.println("perform below assertions on all env");
}

JUnit嵌套测试类

嵌套测试允许创建嵌套类并执行其所有测试方法。
内部类必须是非静态的。
只需使用@Nested注释内部类,即可执行其中的所有测试方法。

@BeforeAll
static void beforeAll() {
   System.out.println("**--- JUnit5Sample4Test :: beforeAll :: Executed once before all test methods ---**");
}
 
@BeforeEach
void beforeEach() {
	 System.out.println("**--- JUnit5Sample4Test :: beforeEach :: Executed before each test method ---**");
}

@AfterEach
void afterEach() {
	 System.out.println("**--- JUnit5Sample4Test :: afterEach :: Executed after each test method ---**");
}

@AfterAll
static void afterAll() {
	 System.out.println("**--- JUnit5Sample4Test :: afterAll :: Executed after all test method ---**");
}
 
   @Nested
   class InnerClass {
 
        @BeforeEach
        void beforeEach() {
             System.out.println("**--- InnerClass :: beforeEach :: Executed before each test method ---**");
        }
 
        @AfterEach
        void afterEach() {
      	   System.out.println("**--- InnerClass :: afterEach :: Executed after each test method ---**");
        }
 
        @Test
        void testMethod1() {
      	   System.out.println("**--- InnerClass :: testMethod1 :: Executed test method1 ---**");
        }
 
        @Nested
        class InnerMostClass {
 
             @BeforeEach
             void beforeEach() {
                  System.out.println("**--- InnerMostClass :: beforeEach :: Executed before each test method ---**");
             }
 
             @AfterEach
             void afterEach() {
          	    System.out.println("**--- InnerMostClass :: afterEach :: Executed after each test method ---**");
             }
 
             @Test
             void testMethod2() {
          	    System.out.println("**--- InnerMostClass :: testMethod2 :: Executed test method2 ---**");
             }
      }
  }

JUnit测试异常

在某些情况下,期望方法在特定条件下引发异常。
如果给定的方法未引发指定的异常,则assertThrows将使测试失败。

Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
   throw new IllegalArgumentException("Illegal Argument Exception occured");
});
assertEquals("Illegal Argument Exception occured", exception.getMessage());

JUnit测试执行

单元测试可以通过多种方式执行,其中两种方式如下:

  • 使用Eclipse IDE Oxygen.3a(4.7.3a)发行并打开要执行的测试文件。
    右键单击文件,然后选择选项Runs As,然后选择JUnit Test
  • 在Windows命令提示符下使用mvn test命令