일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 자바
- 매핑
- 인강리뷰
- javascript
- 회고
- 후기
- 오라클
- Oracle
- 카카오톡1차
- study
- 에러
- 프로그래머스
- JPA
- 우아한테크코스
- Java
- Eclipse
- 독서리뷰
- 인코딩
- Head First Design Pattern
- 람다
- 이펙티브자바
- 알고리즘
- 인프런
- 독서
- 디자인패턴
- Design Pattern
- math
- 공부
- Singleton
- spring
- Today
- Total
Lee's Grow up
[TDD/테스트주도개발] JUnit5 본문
시작하며
해당 내용은 JUnit 5 User Guide
와 인프런의 더 자바, 애플리케이션을 테스트하는 다양한 방법
을 정리한 내용입니다. 잘못된 부분은 댓글로 피드백 부탁드립니다.
- Junit5 User Guide : https://junit.org/junit5/docs/current/user-guide/
- 인프런 : https://www.inflearn.com/course/the-java-application-test/dashboard
개요
이전 버전의 JUnit와는 다르게 JUnit5 부터는 모듈의 집합으로 구성되어 있음, 또한 JUnit5는 java8 이상의 버전을 필요로하나, 그 하위 버전도 JDK로 컴파일된 코드는 계속 테스트 가능JUnit 5 = Junit Platform + Junit Jupiter + JUnit Vintage
Junit Platform
TestEngine
API를 제공해주며, 콘솔 실행 런처를 제공해줍니다.
JUnit Jupiter
TestEngine
API 구현체로 JUnit5 API를 제공
JUnit Vintage
- 하위 버전과 호환을 위해 JUnit3, JUnit4 기반의 테스트 엔진을 제공
어노테이션
JUnit5 어노테이션 | 내용 | JUnit4 어노테이션 |
@Test | 테스트 Method임을 선언 | @Test |
@ParameterizedTest | 매개변수를 받는 테스트를 작성할 수 있다. | |
@RepeatedTest | 반복되는 테스트 작성 가능 | |
@TestFactory | @Test로 선언된 정적 테스트가 아닌 동적으로 테스트를 사용 | |
@TestInstance | 테스트 클래스의 생명주기를 설정 | |
@TestTemplate | 공급자에 의해 여러 번 호출될 수 있도록 설계된 테스트 케이스 템플릿임을 나타낸다. | |
@TestMethodOrder | 테스트 메소드 실행 순서를 구성하는데 사용 | |
@DisplayName | 테스트 클래스 또는 메소드의 사용자 정의 이름을 선언할 때 사용 | |
@DisplayNameGeneration | 이름 생성기를 선언, 예를 들어 '_'를 공백 문자로 치환해주는 생성기가 있다. ex ) new_test -> new test | |
@BeforeEach | 모든 테스트 실행 전에 실행할 테스트에 사용 | @Before |
@AfterEach | 모든 테스트 실행 후에 실행한 테스트에사용 | @After |
@BeforeAll | 현재 클래스를 실행하기 전 제일 먼저 실행할 테스트 작성 static로 선언 | @BeforeClass |
@AfterAll | 현재 클래스 종료 후 해당 테스트를 실행 static로 선언 | @AfterClass |
@Nested | 클래스를 정적이 아닌 중첩 테스트 클래스임을 나타냅니다. | |
@Tag | 클래스또는 메소드 레벨에서 태그를 선언할 때 사용, 이를 메이븐을 사용할 경우 설정에서 테스트를 태그를 인식해 포함하거나 제외시킬 수 있다 | |
@Disabled | 이 클래스나 테스트를 사용하지 않음을 표시 | @Ignore |
@Timeout | 테스트 실행 시간을 선언 후 초과되면 실패하도록 설정 | |
@ExtendWith | 확장을 선언적으로 등록할 때 사용 | |
@RegisterExtension | 필드를 통해 프로그래밍 방식으로 확장을 등록할 때 사용 | |
@TempDir | 필드 주입 또는 매개변수 주입을 통해 임시 디렉토리를 제공하는데 사용 |
각각 어노테이션의 사용법은 추후 시간이 나면 포스팅하고, 참고할 만한 링크를 남깁니다. 위에 링크로 연결된 JUnit5 User Guide 또는 아래 링크에서 사용법 설명을 볼 수 있습니다.
baeldung : https://www.baeldung.com/?s=Guide+JUnit5
사용자 정의 어노테이션
JUnit Jupiter의 주석은 메타 주석 으로 사용할 수 있습니다.
예를 들어 @Tag("fast")
를 매번 사용하는 대신 @FAST
로 정의하여 사용 가능
Fast Annotation
@Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Tag("fast") public @interface Fast { }
Test Method
@Fast @Test void myFastTest() { ... }
나아가
@Fast
,@Test
를 섞은@FastTest
로도 선언가능@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Tag("fast") @Test public @interface FastTest { }
테스트 클래스 및 메소드 작성
Test Class : 최소한 하나의 테스트 메소드를 포함하는 최상위 클래스를 말하며, abstract
이면 안되고, single constructor
이어야 한다.
Test Method : @Test
, @RepeatedTest
, @ParameterizedTest
, @TestFactory
, @TestTemplate
로 선언된 테스트 메소드
Lifecycle Method : @BeforeAll
, @AfterAll
, @BeforeEach
, @AfterEach
로 선언된 메소드
작성 예시
class MyTest{ @BeforeAll static void initAll(){ } @BeforeEach void init(){ } @Test void standardTest() { } @Test @Disabled("description 작성, 데모용 테스트") void disabledTest(){ } @Test void abortedTest() { assumeTrue("abc".contains("Z")); fail("test should have been aborted"); } @AfterEach void tearDown() { } @AfterAll static void testDownAll() { } }
위와 같이 간단하게 테스트를 작성했다고 가정하면 실행 순서는
initAll() -> init() -> standardTest() -> tearDown() -> init() -> abortedTest() -> tearDown() -> testDownAll()
순으로 동작하게 된다.
JUnit5 Assertions
기본적으로 JUnit4의 Assertions를 포함하며 java 8 람다와 함께 사용하기 위해 몇가지를 추가했습니다. 모든 JUnit Jupiter 어셜션은 클래스의 static
메소드입니다. org.junit.jupiter.api.Assertions
메소드 | 설명 |
assertAll ( executables...) | 구문 오류시 예외를 발생시키지 않으면서 한번에 모든 구문을 확인 할 수 있습니다. |
assertEquals( expected, actual ) | 실제 값과 예상 값이 같은지 확인, 이 외 assertArrayEquals(), assertNotEquals() 도 존재 |
assertNotNull( actual ) | 값이 null인지 아닌지 확인 |
assertTrue( boolean ) | 다음 조건이 참인지 확인 |
assertThrows( expectedType, executable ) | 예외를 발생 시키는지 확인 |
assertTimeout ( timeout, executable ) | 특정 시간안에 실행하는지 확인 |
assertTimeoutPreemptively( timeout, executable ) | 특정 시간안에 실행하는지 확인 후, 시간을 초과하면 실행 파일의 실행이 중단되도록 설정. 단, executable와 다른 스레드에서 실행하기 때문에, 원치 않는 결과가 발생할 수 있다. ex ) 트랜잭션이 적용이 안되서 롤백이 안되는 경우 |
이 외 assertSame()등, 많은 메소드가 존재하니 자세한 내용은 아래 API 링크를 통해 참고하시면 될 것 같습니다.
JUnit5 Assertions API : https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/Assertions.html
그 외 써드파티 라이브러리로 AssertJ
, Hamcrest
, Truth
등을 사용할 수 있습니다.
작성 예시
객체 생성 테스트
@Test void create_new_member{ Member member = Member.builder() .name("Lee") .build(); assertNotNull(member); assertEquals("Lee", member.getName()); }
위와 같이 객체 생성이 정상적으로 되었는지, 값이 원하는 값인지 확인하는 테스트를 작성할 수 있습니다.
또한 assert에는 마지막 인자로String
또는Supplier<String>
를 통해 메세지를 출력할 수 있습니다.테스트 결과 오류메세지 설정
@Test void create_new_member{ Member member = Member.builder() .name("Lee") .build(); // assertEquals("Park", member.getName(), "생성된 member의 name이 Lee가 아닙니다."); assertEquals("Park", member.getName(), () -> "생성된 member의 name이 Lee가 아닙니다."); }
Exception 확인
Member에 age라는 필드를 추가해주고 생성자를 통해 생성 시 음수가 들어오면 Exception을 발생하도록 로직을 만들어 줍니다.public Class Member { private int age; public Member(int age) { if( age < 0 ) throw new IllegalArgumentException(); this.age = age; } }
위와 같이 Member 클래스가 있을 경우 아래와 같이 테스트 작성 가능
@Test void create_new_member{ assertThrows(IllegalArgumentException.class, () -> new Member(-100)); }
나아가 Exception 타입으로 리턴값을 받을 경우 해당 exception을 활용가능
@Test void create_new_member{ IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new Member(-100)); // excetpion 활용.. }
assertTimeout
시간에 대한 제한을 줄 경우 사용void create_new_member{ assertTimeout(Duration.ofSeconds(2), () -> { new Member(); Thread.sleep(3000); }); }
해당 assertion의 경우 시간제한을 2초로 주었지만, 실제 실행인 3초 이상까지 테스트가 실패하는 경우에도 실행을 하게 됩니다. 이럴 경우 사용하는 assertion이
assertTimeoutPreemptively
이며 사용법은 동일합니다.
다만ThreadLocal
을 사용하는 경우 예상치 못한 예외를 발생할 수 있기 때문에 사용에 주의해야 합니다.
'Agile > TDD(Test Driven Development)' 카테고리의 다른 글
[TDD/테스트주도개발] TDD 개념 (0) | 2020.01.03 |
---|