-
[JUnit] Spring Boot 테스트하기 ( Migration from JUnit4 to JUnit5 )IT/JAVA | Spring 2023. 4. 30. 17:41
Junit5의 요약된 기초지식에 대한 내용은 아래에서 확인 가능하다.
2023.02.18 - [IT/JAVA | Spring] - [JUnit] JUnit5 기초지식 정리( 설정, annotation, assertions )
JUnit5 기초지식 annotation 정리 1
2023.02.25 - [IT/JAVA | Spring] - [JUnit] JUnit5 기초지식 annotation 정리
junit을 이용해서 통합테스트를 진행하는 경우 spring boot 테스트를 진행하는 경우가 있다.
우선 spring boot를 테스트 한다는것은 테스트에 소모되는 자원이 많아져 시간이 오래걸리거나 부하가 발생할 수 있다.
@SpringBootTest annotation이 붙어있는 테스트 클래시가 실행되면
@SpringBootApplication annotation을 찾아 모든 빈을 로드하기 때문이다.
덕분에 실제 코드처럼 의존성 주입하여 사용가능하나 테스트가 많이 무거워지게 된다.
또한 실제 빈을 주입받아 테스트하게 됨으로 데이터를 삽입하거나 삭제하면 실제 데이터의 변화가 생길 수 있다.
의도한게 아니라면 꼭 @Transactional을 이용하여 rollback처리하도록한다.
1. Junit Spring boot 설정 차이
우선 springboot test를 위한 junit4와 junit5의 변경점을 확인한다.
설명 JUnit 4 JUnit 5 @Test annotation import 변경 org.junit.Test org.junit.jupiter.api.Test 이름이 변경된 annotation @RunWith @ExtendWith @SpringRunner @SpeingExtension public 접근제어자 제거 public 명시 public을 명시하지 않아도 된다. 더 많은 Annotation은 아래 글에서 확인한다.
2023.02.18 - [IT/JAVA | Spring] - [JUnit] JUnit5 기초지식 정리( 설정, annotation, assertions )
// JUnit4 @RunWith(SpringRunner.class) @SpringBootTest public class JUnit4TestClass { } // JUnit5 // JUnit5의 @SpringBootTest에는 @ExtendWith(SpringExtension.class)가 선언되어있다. @SpringBootTest public class JUnit5TestClass { }
JUnit5의 @SpringBootTest annotation을 보면 @ExtendWith(SpringExtension.class)가 선언되어있다.
2. 의존성 주입
@SpringBootTest는 @SpringBootApplication 어노테이션을 찾아서 모든 빈을 로드한다.
JUnit에서 의존성주입할때 주의해야할 몇가지가 있다.
일반적인 의존성주입 방법은 다양하지만 일반적으로 4가지방법을 사용한다.
1. 생성자를 통해 의존성주입
2. 필드를 통해서 의존성 주입
3. setter를 통한 의존성 주입
4. lombok을 이용한 final 필드에 의존성 주입
JUnit에서 의존성 주입을 하기 위해 다양한 방법을 시도하겠지만 간단한 방법은 @AutoWired를 사용하는것이다.
생성자나 lombok방식을 사용하게되면 에러가 발생할것이다.
에러가 발생하는 원인은 JUnit5가 DI를 스스로 지원한다.
또한 DI를 지원하는 타입이 정해져있다
JUnit5에서 생성자나 lombook을 이용할 수 없는 이유는 JUnit이 생성자에 의존성 주입하려고 먼저 개입하기 때문이다.
자세한 내용은 아래 블로그를 참고한다.
https://pinokio0702.tistory.com/189
@SpringBootTest class JUnit5TestClass { // 의존성 주입은 @AutoWired를 이용한다. @AutoWired TestService testservice; }
3. 테스트 순서와 인스턴스 생명주기 정하기
보통의 통합테스트라면 의도된 순서에 따라 인스턴스를 공유하고 변경된 데이터의 흐름에 따라 테스트를 지정하겠지만
JUnit은 테스트의 순서를 보장하지 않으며 그로인하여 의도하지않은 방향으로 테스트가 진행될 수 있다.
테스트 순서는 @TestMethodOrder(OrderAnnotation.class), @Order 어노테이션을 이용할 수 있다.
// 생명주기를 class단위로 한다면 테스트순서를 지정하는게 좋다. @SpringBootTest @TestMethodOrder(OrderAnnotation.class) class JUnit5TestClass { // 의존성 주입은 @AutoWired를 이용한다. @AutoWired TestService testservice; @DisplayName("출력되는 테스트 명을 입력한다.") @Order(1) @Timeout(1) @Test void testAnnotation() throws InterruptedException { log.info("testAnnotation"); assertEquals("test","test"); Thread.sleep(2000); } @Test @Order(3) void test_under_scores() { log.info("test_under_scores"); assertEquals("test","test"); } @DisplayName("출력되는_테스트_명을_입력한다.") @Order(2) void test_display_name_under_scores() { log.info("test_display_name_under_scores"); assertEquals("test","test"); } }
인스턴스 생명주기는 @TestInstance를 이용하여 설정할 수 있다.
@TestInstance는 파라메타로 Lifecycle를 받는다.
Lifecycle 종류는 아래 표와 같다.
Lifecycle 설명 Lifecycle.PER_CLASS 클래스 단위로 인스턴스 생성
테스트 메소드간 영향을 받는다.
테스트 순서를 신경써야한다.Lifecycle.PER_METHOD 메소드 단위로 인스턴스 생성
테스트 메소드간 영향을 받지 않는다.
연계되어야하는 테스트에선 앞선 테스트 데이터를 전달받지 못한다.// 생명주기를 class단위로 한다면 테스트순서를 지정하는게 좋다. @SpringBootTest @TestMethodOrder(OrderAnnotation.class) @TestInstance(Lifecycle.PER_CLASS) class JUnit5TestClass { // 의존성 주입은 @AutoWired를 이용한다. @AutoWired TestService testservice; @DisplayName("출력되는 테스트 명을 입력한다.") @Order(1) @Timeout(1) @Test void testAnnotation() throws InterruptedException { log.info("testAnnotation"); assertEquals("test","test"); Thread.sleep(2000); } @Test @Order(3) void test_under_scores() { log.info("test_under_scores"); assertEquals("test","test"); } @DisplayName("출력되는_테스트_명을_입력한다.") @Order(2) void test_display_name_under_scores() { log.info("test_display_name_under_scores"); assertEquals("test","test"); } }
4. 테스트 데이터 롤백
기본적으로 테스트에서 @Transactional의 디폴트는 Rollback = true이다.
별다른 세팅없이 클래스나 메소드에 @Transactional을 세팅하면 모두 롤백된다고 생각하며 된다.
허나 의도적으로 Rollback하지 않으려면 @Rollback(false)를 세팅해주면 된다.
// 생명주기를 class단위로 한다면 테스트순서를 지정하는게 좋다. @SpringBootTest @TestMethodOrder(OrderAnnotation.class) @TestInstance(Lifecycle.PER_CLASS) @Transactional // 디폴트는 Rollback = true class JUnit5TestClass { // 의존성 주입은 @AutoWired를 이용한다. @AutoWired TestService testservice; @DisplayName("출력되는 테스트 명을 입력한다.") @Order(1) @Timeout(1) @Rollback(false) // 이 테스트 메소드는 rollback하지 않는다. @Test void testAnnotation() throws InterruptedException { log.info("testAnnotation"); assertEquals("test","test"); Thread.sleep(2000); } @Test @Order(3) void test_under_scores() { log.info("test_under_scores"); assertEquals("test","test"); } @DisplayName("출력되는_테스트_명을_입력한다.") @Order(2) void test_display_name_under_scores() { log.info("test_display_name_under_scores"); assertEquals("test","test"); } }
Reference
https://junit.org/junit5/docs/current/user-guide/
https://www.baeldung.com/junit-5
https://junit.org/junit5/docs/current/user-guide/#writing-tests
https://pinokio0702.tistory.com/189
https://go-coding.tistory.com/89https://velog.io/@fftl/SpringBoot-junit5-Test
'IT > JAVA | Spring' 카테고리의 다른 글
[JUnit] JUnit5 @Tag 를 이용한 필터링 및 그룹만들기 (0) 2023.03.12 [JUnit] JUnit5 기초지식 annotation 정리 (0) 2023.02.25 [JUnit] JUnit5 기초지식 정리( 설정, annotation, assertions ) (0) 2023.02.18 [JUnit] Junit test code에서 lombok @Slf4j 동작하지 않음 ( Cannot resolve symbol 'Slf4j' ), gradle (1) 2023.02.11 [JAVA] 특수문자 > 숫자(0123~순, 소수점 포함) > 영어(대문자 먼저, abc~순) > 한글(ㄱㄴㄷ~순) 순서 Custom Comparator로 String 정렬 (0) 2023.01.28