개발을 자주 하면 할 수록 테스트가 점점 중요하다는 생각을 가지게 된다.
발생할 문제를 미연에 방지할 수도 있고, 정상적으로 동작되는 지 역시 알 수 있기 때문이다.
이 중에서 스프링을 오래 다뤄분 들이라면 이미 알고 계시겠지만, 스프링을 통한 테스트를 자주 하지 않은 분들을 위해 글을 작성하게 되었다.
스프링에서 테스트하는 방법은 여러 가지가 있지만, 가장 대표적인 방법은 아마 @SpringBootTest
어노테이션을 통해 테스트 클래스로 지정하는 것이다.
그리고 레이어마다 각기 편의한 어노테이션들 역시 제공해주고 있다.
예를 들면 Jpa 환경에서는 @DataJpaTest
를, Controller, Filter, WebMvcConfigurer 들을
테스트하고 싶다면 @WebMvcTest
을, REST 통신의 JSON 형식이 예상대로 응답을 반환하는 지를 테스트할 때는 @RestClientTest
을 사용하는 등 여러 어노테이션들을 제공해주고 있다.
그렇다면, 커스텀 컴포넌트를 테스트해야 한다면 어떻게 하는 것이 좋을 까?
우선, 모든 컴포넌트를 로드하는 @SpringBootTest
가 방법이 될 수 있지만, 개인적으로 추천하진 않는다. 좋은 테스트를 위해서는 FIRST를 지키는 것이 좋다.
(FIRST에 대해서는 이 링크를 참고하자.)
FIRST에서 말하기를 "테스트는 빠르게 동작하여 자주 시연할 수 있어야한다."
빠른 동작을 위해서는 @SpringBootTest
는 사용해서는 안된다.
필요하지 않은 컴포넌트들까지 전부 로드하기 때문이다.
필자가 가장 추천하는 방법은 @ContextConfiguration
을 기반으로 하는 테스트이다.
꼭 필요한 컴포넌트들만 로드할 수 있기에 가볍기 때문이다.
또, 필요에 따라서 클래스를 추가하거나 할 수 있기 때문이다.
@ContextConfiguration(classes = {
...추가할 컴포넌트 클래스들
})
아래는 실제 필자가 JWT 토큰 생성 및 검증을 테스트한 코드 중 일부이다.
@ExtendWith(SpringExtension.class)
@TestPropertySource(locations = "classpath:test.properties")
@ContextConfiguration(classes = {
TokenManager.class,
TokenProperty.class,
JsonWebTokenGenerator.class /** 반드시 구현체를 주입받아야하기에 구현체 직접 주입 */
})
@ConfigurationPropertiesScan(basePackageClasses = TokenProperty.class)
class TokenManagerTest {
@Autowired
private TokenManager tokenManager;
@ParameterizedTest
@ValueSource(longs = { 1, 12, 144, 99, 51143, 573 }
void generateAndVerifyToken(long id) {
//given -> already given by parameter
//when
final String token = tokenManager.generateAccessToken(id);
//verify
assertThat(token).isNotBlank();
assertThat(tokenManager.authenticateToken(token, TokenType.ACCESS))
.isEqualTo(id);
}
}
@ConfigurationProperties
를 사용하는 클래스가 있는 경우, 그냥 동작하는 경우도 있지만
만일 되지 않는 경우 직접 @ConfigurationPropertiesScan
을 통해 지정해주면 동작할 것이고,
실제 프로퍼티와 다른 프로퍼티를 지정해주고 싶은 경우, @TestPropertySource
를 사용하면 된다.
Cannot process locations AND classes for context configuration ...(중략) configure one or the other, but not both
이라는 에러가 발생하기에 반드시 구현체를 작성해야한다.