JUnit5チュートリアル

JUnit5のチュートリアル

このJunitチュートリアルでは、Junit5の基本と新機能を例を使って紹介します。Javaの世界では、JunitはJavaコードに対してユニットテストを実装するためによく使われるフレームワークの一つです。Junitは主に開発者が自分自身でJVM上でコードをテストするのを助ける役割を果たしています。

JUnit5アーキテクチャ

junit5 architecture

JUnitプラットフォーム

  • Launches testing frameworks on the JVM
  • Has TestEngine API used to build a testing framework that runs on the JUnit platform

JUnit Jupiter を日本語で説明すると、以下のように言い換えることができます。

「JUnit Jupiter」とは、Javaのユニットテストフレームワークのひとつです。

  • Blend of new programming model for writing tests and extension model for extensions
  • Addition of new annotations like @BeforeEach, @AfterEach, @AfterAll, @BeforeAll etc.

JUnit ビンテージ

  • Provides support to execute previous JUnit version 3 and 4 tests on this new platform

JUnitのMavenの依存関係

JUnit5ベースのテストケースをプロジェクトに実装するためには、プロジェクトのpom.xmlファイルに以下の依存関係を追加してください。

  • JUnit 5 Library
<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 provider to execute the unit tests where IDE does not have JUnit5 support (if IDE has support then this point is not required)
<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のアノテーション

以下には、いくつかの一般的に使用される注釈が提供されています。 (Ika ni wa, ikutsu ka no ippan-teki ni shiyou sareru chūkai ga teikyō sa reteimasu.)

Annotation Description
@Test Denotes a test method
@DisplayName Declares a custom display name for the test class or test method
@BeforeEach Denotes that the annotated method should be executed before each test method
@AfterEach Denotes that the annotated method should be executed after each test method
@BeforeAll Denotes that the annotated method should be executed before all test methods
@AfterAll Denotes that the annotated method should be executed after all test methods
@Disable Used to disable a test class or test method
@Nested Denotes that the annotated class is a nested, non-static test class
@Tag Declare tags for filtering tests
@ExtendWith Register custom extensions
package com.scdev;

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 ---**");
  }


}
Junit 5 tutorial, eclipse run junit test

JUnitのアサーション

すべてのテストメソッドは、アサーションを使用して条件が真であることを評価する必要があります。これにより、テストが続行されます。JUnit Jupiter のアサーションは、org.junit.jupiter.api.Assertions クラスに保持されています。すべてのメソッドは静的です。

Assertion Description
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ではありません。また、テストメソッドはpublicである必要はありませんし、ローカルなパッケージ内である必要もありません。

import org.junit.jupiter.api.Test;

JUnit5の前提条件

前提条件は、org.junit.jupiter.api.Assumptionsクラスの静的メソッドです。指定された条件が満たされていない場合は、テストは実行されません。中止されたテストはビルドの失敗を引き起こしません。前提条件が失敗すると、org.opentest4j.TestAbortedExceptionがスローされ、テストはスキップされます。

Assumptions Description
assumeTrue Execute the body of lamda when the positive condition hold else test will be skipped
assumeFalse Execute the body of lamda when the negative condition hold else test will be skipped
assumingThat Portion 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 テストの実行

ユニットテストは様々な方法で実行できますが、以下の2つの方法があります:

  • Use Eclipse IDE Oxygen.3a (4.7.3a) Release and open test file to be executed. Right-click on the file and choose option Runs As followed by JUnit Test
  • Use mvn test command on Windows command prompt

要約すると、以下のようになります。

私たちは、いくつかの例を使ってJUnit5とその新機能を探索しました。また、JUnitの注釈、アサーション、前提条件、例外をどのように使用し、ネストされたテストクラスを書くことができるかも見てみました。

当社のGitHubリポジトリから、完全なサンプルプロジェクトをダウンロードすることができます。

コメントを残す 0

Your email address will not be published. Required fields are marked *