@DataJpaTest
public class JpaTest {
}
JPA Repository를 테스트하기 위한 테스트코드를 작성하기 위해서 @DataJpaTest라는 어노테이션이 필요하다는 것을 알게 되었습니다.
DataJpaTest 어노테이션?
Spring에서 JPA 관련 테스트 설정만 로드한다. DataSource의 설정이 정상적인지, 제대로 생성 수정 삭제 조회 하는지 등의 테스트가 가능하다.
출처: https://0soo.tistory.com/40 [Lifealong:티스토리]
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource
[org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]:
Unsatisfied dependency expressed through method 'dataSourceScriptDatabaseInitializer' parameter 0:
Error creating bean with name 'dataSource':
Failed to replace DataSource with an embedded database for tests.
If you want an embedded database please put a supported one on the classpath or
tune the replace attribute of @AutoConfigureTestDatabase.
그런데 다음과 같은 오류가 발생했습니다. 대충 읽어보면, dataSource와 관련해서 문제가 생긴 것 같네요. 그리고 이건 곧 DB와 관련된 문제겠네요. 저는 MySQL을 사용하고 있고 테스트도 이걸로 진행하고 있습니다.
관련 키워드로 검색하니 스택오버플로우에서 관련 질문글을 금방 찾을 수 있었습니다.
@DataJpaTest를 사용할 경우, Default로 EmbededDatabase (H2)를 사용하도록 되어 있다고 하네요. 하지만 저는 application.yml에서도 MySQL로 설정했었기 때문에 관련 DB를 찾을 수 없어서 오류가 난 케이스입니다.
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class JpaTest {
}
@AutoConfigureTestDatabase 어노테이션을 추가로 달아서, 기본값을 사용하지 않도록 설정합니다. 그러면 application.yml에 설정되어 있는 DB를 읽어서 연결처리를 할테니 문제가 해결됩니다.
혹은 Test용 설정이 따로 있는 경우, 아래와 같이 프로필을 추가하고 활성화해도 됩니다.
@DataJpaTest
@ActiveProfiles("test")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class JpaTest {
}
application.yml에 설정 추가하기spring:
test:
database:
replace: none
혹은 application.yml에 위와 같이 replace 옵션을 none으로 하는 방법도 있습니다.
@DataJpaTest를 사용하는 단위테스트에서는 당연하게도 @Autowired를 통한 주입을 받을 수 없습니다. @SpringBootTest를 통한 통합테스트가 아니고, 그렇기에 Component Scan을 하지 않아 컨테이너에 @Component 빈들이 등록되지 않습니다.
단위테스트에서는 @BeforeAll이나 @BeforeEach를 활용하여 테스트케이스가 실행되기 전에 필요한 컴포넌트를 직접 생성하여 사용해야 합니다.
@DataJpaTest
@ActiveProfiles("test")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class JwtServiceTest {
@Autowired
private UserRepository userRepository;
private static JwtService jwtService;
private static BCryptPasswordEncoder bCryptPasswordEncoder;
@BeforeAll
public static void setUp() {
jwtService = new JwtService();
// @Value는 IOC 컨테이너를 거치지 않았기 때문에, ReflectionTestUtils를 통해 강제로 주입.
ReflectionTestUtils.setField(jwtService, "secret", "secretkey");
ReflectionTestUtils.setField(jwtService, "accessTokenExpiration", 3600);
ReflectionTestUtils.setField(jwtService, "refreshTokenExpiration", 86400);
jwtService.init();
bCryptPasswordEncoder = new BCryptPasswordEncoder();
}
@Test
@DisplayName("유저정보를 기반으로 생성된 토큰을 검증")
void JwtTest() {
...
}
}
참고로,
@DataJpaTest에는@Transactional어노테이션이 포함되어 있습니다. JUnit을 통한 Test에서@Transactional은 SELECT를 제외한 모든 쿼리는 Rollback 대상으로 취급합니다.
그래서 테스트에서 건드린 내용은 커밋되지 않고, 롤백됩니다.