SpringBoot 프로젝트에서 기능들의 유닛테스트를 진행하기 위해서 테스트 코드를 작성하려 한다. 테스트 코드를 작성하기 위해서 JUnit 이라는 테스트 프레임워크를 사용하려고 한다. JUnit 은 자바 테스트 프레임워크로 다양한 어노테이션과 메서드를 통해서 테스트 코드 작성을 편리하게 해준다.
1. JUnit 이란?
JUnit 이란 자바 프로그래밍 언어용 단위 테스트 프레임워크이다. @Test, @BeforeEach, @AfterEach 와 같은 어노테이션을 기반으로 테스트를 지원한다. 그리고 단정문 (Assert) 메서드를 통해서 테스트 케이스의 사용자의 기대값에 대한 기능의 수행 결과를 확인할 수 있다. assert 메서드의 결과는 테스트 케이스의 성공 실패 여부를 반환한다.
JUnit 은 3가 모듈로 구성되어 있다. Jupiter, Platform, Vintage 3개의 모듈로 구성되는데, Jupiter 는 TestEngine API 구현체로 JUnit5 를 구현하고 있다. Platform 은 각종 IDE 에서 Test 를 실행하기 위해 IDE 와의 연동을 보조하는 역할을 한다. Vintage 는 TestEngine 구현체로 JUnit3, 4 를 구현하고 있다.
2. JUnit 환경 설정
JUnit 을 SpringBoot 에서 사용하기 위해서는 build.gradle 에서 환경설정을 선행해야 한다.
test {
useJUnitPlatform()
}
dependencies {
...
testImplementataion 'org.springframework.boot:spring-boot-starter-test'
...
}
build tool 인 gradle 에서 사용할 unit test platform 을 지정할 수 있는데, 여기서 useJUnitPlatform() 으로 JUnit 라이브러리를 지정해준다. 그리고 JUnit 을 사용하기 위한 dependency 도 추가한다. SpringBoot 에서는 spring-boot-starter-test 라이브러리에 JUit 을 포함하고 있기 때문에 해당 라이브러리의 의존성을 추가하면 된다.
3. JUnit 어노테이션
JUnit Life Cycle
JUnit 은 어노테이션 기반의 프레임워크로 테스트 클래스의 메서드에 붙어있는 어노테이션에 따라서 실행 순서가 결정된다.
@Test | 테스트용 메서드를 표현하는 어노테이션 |
@BeforeEach | 각 테스트 메서드의 실행 전에 선행되는 메서드의 어노테이션 |
@AfterEach | 각 테스트 메서드의 실행 후에 실행되는 메서드의 어노테이션 |
@BeforeAll | 테스트 시작 전에 실행되어야 하는 메서드의 어노테이션. Static 메서드에만 표시할 수 있다. |
@AfterAll | 테스트 종료 후에 실행되어야 하는 메서드의 어노테이션. Static 메서드에만 표시할 수 있다. |
JUnit 테스트 환경 설정 어노테이션
@SpringBootTest
SpringBoot 에서 통합 테스트를 위해 주로 사용하는 어노테이션이다.
SpringBoot application 을 실행헀을 때와 같이 @SpringBootApplication 을 찾아가 하위의 Bean 을 스캔하여 ApplicationContext 에 모든 Bean 을 등록한다. (ComponentScan) 그 후에 테스트용 Application Context 를 만들어서 Bean 을 추가하고, MockBean 을 찾아서 교체한다.
@DataJpaTest
ApplicationContext 에 JPA 에 필요한 설정들만 등록한다. 기본적으로 in-memory embedded 저장소를 사용한다. ComponentScan 을 하지 않기 때문에 컨테이너의 @Component 로 지정된 Bean 들이 자동으로 등록되지 않는다.
@SpringBootTest 는 @Component 어노테이션이 붙은 클래스를 테스트하는 경우에 사용한다. 반면에 @DataJpaTest 는 그렇지 않는 경우 @Repository 등에 대해서 테스트할 때 사용한다.
ApplicationContext 에 모든 Bean 들이 등록되지 않기 때문에 테스트 속도가 @SpringBootTest 보다 빠르다.
@WebMvcTest(class)
Class 명으로 할당된 클래스만 실제로 로드하여 테스트를 수행한다.
매개변수를 지정해주지 않으면 @Controller, @RestController, @RestControllerAdvice 등 컨트롤러와 관련된 Bean 이 모두 로드된다. 스프링의 모든 Bean 을 로드하는 @SpringBootTest 대신에 컨트롤러 관련 코드만 테스트 하는 경우에 사용한다.
@ExtendWIth
JUnit4 에서 @RunWith 으로 사용되던 어노테이션의 변경된 버전이다.
@ExtendWIth 를 사용하여 메인으로 실행될 클래스를 지정할 수 있다.
@SpringBootTest 는 기본적으로 @ExtendWith 를 포함하고 있다.
@Autowired
@Autowired 어노테이션은 기본 SpringBoot application 에서 사용되는 것과 같이 등록된 Bean 에서 해당 타입의 Bean 을 찾아서 주입해주고 이를 테스트에 사용할 수 있도록 해준다.
만약 MockMvc 타입으로 선언된 컨트롤러의 API 를 테스트하는 용도인 MockMvc 객체를 주입 받는다. perform(), andExpect(), andDo(), andReturn() 등의 메서드를 활용하여 컨트롤러에 요청을 보내고 응답에 대한 테스트를 수행할 수 있다.
@MockBean
테스트할 클래스에서 주입받고 있는 객체에 대해 가짜 객체를 생성해주는 어노테이션이다.
해당 객체는 실제 동작을 하지는 않는다. 대신 given() 메서드를 활용하여 가짜 객체의 동작에 대해 정의하여 사용할 수 있다.
@AutoConfigureMockMvc
spring.test.mockmvc 의 설정을 로드하면서 MockMvc 의 의존성을 자동으로 주입한다.
MockMvc 클래스는 REST API 테스트를 할 수 있는 클래스이다.
@Import
필요한 Class 들을 Configuration 으로 만들어 사용할 수 있다. Configuration Component 클래스도 의존성을 설정할 수 있다. Import 된 클래스는 주입으로 사용할 수 있다.
@TestPropertySource
테스트 환경에서 사용할 환경 설정을 따로 설정하고 로드할 때 사용한다.
@TestPropertySource("classpath:appliaction-test.properties") 와 같은 형식으로 사용하여 해당 프로젝트의 classpath 에서 주어진 이름의 설정 파일을 찾아서 환경 설정을 한다. 예시의 경우 application-test.properties 를 사용하여 테스트를 수행한다.
4. 테스트 코드 구현
@SpringBootTest
@TestPropertySource("classpath:application-test.properties")
public class TestServiceTest {
@Autowired
TestService testService;
@BeforeEach
void setup() {
System.out.println("setup before each test");
}
@AfterEach
void tearDown() {
System.out.println("tear down after each test");
}
@BeforeAll
static void setupAll() {
System.out.println("setup before all test");
}
@AfterAll
static void tearDownAll() {
System.out.println("tear down after all test");
}
@Test
void testHello() {
String hello = testService.helloTest();
assertEquals("Hello Test", hello);
}
@Test
void testTest() {
assertEquals(1 + 1, 2);
}
}
위의 예제는 testHello() 와 testTest() 두개의 테스트 케이스에 대해서 테스트를 수행하는 코드이다.
두개의 테스트 케이스에는 @Test 어노테이션을 붙여서 테스트 케이스로 지정하고 각각의 메서드에서 assert 메서드를 사용해서 테스트를 수행한다.
이 예제에서는 @SpringBootTest 어노테이션과 @TestPropertySource 두개의 어노테이션을 통해서 테스트 환경 설정한다. @SpringBootTest 를 통해서 실제 SpringBoot 실행환경과 같이 ApplicationContext 에 Bean 을 등록하여 테스트에 사용한다. 이 예제에서는 @Autowired 로 지정된 testService 에 TestService 가 주입되어 사용된다. @TestPropertySource 에서는 classpath 에 있는 application-test.properties 파일로 실행 환경을 설정한다.
테스트 케이스 수행 전후에 실행하기위해 @BeforeAll, @AfterAll, @BeforeEach, @AfterEach 가 붙은 메서드들이 구현되어 있다. @BeforeAll 과 @AfterAll 은 전체 테스트가 실행되기 전후에 한번씩, @BeforeEach 와 @AfterEach 는 각 테스트 케이스 전후에 실행된다. @BeforeAll 과 @AfterAll 로 지정되는 메서드들은 기본적으로 static 으로 선언되어야 한다.
[Reference]
- https://jungguji.github.io/2020/07/05/H2-DB%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-Repository-Test/
- https://da-nyee.github.io/posts/spring-springboottest-vs-datajpatest/
- https://thalals.tistory.com/273
- https://smpark1020.tistory.com/163
'Tech > Spring | SpringBoot' 카테고리의 다른 글
[SpringBoot] 예외처리 - 2 (HandlerExceptionResolver) (0) | 2022.12.08 |
---|---|
[SpringBoot] 예외처리 - 1 (BasicErrorController) (0) | 2022.12.07 |
[SpringBoot] SpringBoot 에 lombok 적용하기 (0) | 2022.11.11 |
[Spring] Database 연동 - 4 (JPA) (0) | 2022.10.22 |
[SpringBoot] Logging - 2 (Logback) (0) | 2022.10.05 |