웹사이트 검색

JUnit5 튜토리얼


JUnit5 튜토리얼

이 Junit 튜토리얼에서는 예제를 사용하여 JUnit5의 기본 사항과 새로운 기능을 소개합니다. Java 세계에서 JUnit은 Java 코드에 대한 단위 테스트를 구현하는 데 사용되는 인기 있는 프레임워크 중 하나입니다. JUnit은 주로 개발자가 스스로 JVM에서 코드를 테스트하는 데 도움이 됩니다.

JUnit5 아키텍처

JUnit 플랫폼

  • JVM에서 테스트 프레임워크 시작
  • JUnit 플랫폼에서 실행되는 테스트 프레임워크를 빌드하는 데 사용되는 TestEngine API가 있습니다.

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>

  • IDE가 JUnit5를 지원하지 않는 경우 단위 테스트를 실행하기 위한 JUnit5 maven 확실한 공급자(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 주석

다음은 일반적으로 사용되는 몇 가지 주석입니다.

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.journaldev;

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 주장

모든 테스트 메서드는 테스트가 계속 실행될 수 있도록 어설션을 사용하여 조건을 참으로 평가해야 합니다. 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.Test가 아닌 org.junit.jupiter.api.Test import 문이 필요합니다. 또한 테스트 메서드는 공용 및 로컬 패키지일 필요가 없습니다.

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 테스트 예외

메서드가 특정 조건에서 예외를 throw할 것으로 예상되는 상황이 있습니다. assertThrows는 주어진 메서드가 지정된 예외를 throw하지 않는 경우 테스트에 실패합니다.

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 테스트 명령 사용

요약

몇 가지 예를 통해 JUnit5와 새로운 기능을 살펴보았습니다. 또한 JUnit 주석, 어설션, 가정, 예외를 사용하고 중첩된 테스트 클래스를 작성하는 방법도 살펴보았습니다.

GitHub 리포지토리에서 전체 예제 프로젝트를 다운로드할 수 있습니다.