뉴스피드에서 댓글 파트를 맡았다.
해당 파트는 유저, 뉴스피드 작업이 완료되어야지만 실질적으로 테스트가 가능하다.
그래서 테스트 어플리케이션을 만들어서 돌려보고자 했다.
굉장히 많은 에러를 접했는데.. 천천히 몇개만 풀어보겠다.
@Test
void createComment_success() throws Exception {
// 테스트용 유저 생성
User user = new User("testuser@example.com", "password");
userRepository.save(user);
User 를 생성하려고 했더니
❌ Expected 6 arguments but found 2 에러가 났다.
User 와 NewsFeed 파트는 건들 수 없으니,
임시로 User 엔티티를 Builder 로 생성하여 저장만 하고 ID만 사용함으로써 해결했다.
// 테스트용 유저 생성
User user = User.builder()
.email("testuser@example.com")
.password("password123")
.name("테스터")
.mbti(MBTI.INTP)
.idNum("990101")
.status(UserStatus.ACTIVE)
.build();
userRepository.save(user);
DataSourceAutoConfiguration.PooledDataSourceConfiguration#jdbcConnectionDetails matched:
- @ConditionalOnMissingBean (types: org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails; SearchStrategy: all) did not find any beans (OnBeanCondition)
테스트코드를 실행했더니 해당 메시지가 출력됐다.
이것은 Spring Boot 의 Conditions EvaluationReport 이며, 어떤 자동 설정(AutoConfiguration) 이 활성화되었는지 알려주는 디버깅용 로그라고 한다.
해당 메시지가 의미하는 바는,
H2나 MySQL 등 데이터베이스 설정 누락되어 있어서, DataSource(JDBC 연결 정보) 를 못 찾고 있다는 뜻이라고 한다.
해결 방법으로는 두 가지가 있다.
1.application.yml
또는application.properties
에 DB 설정 추가
2. 테스트 클래스에서 DB 설정 직접 넣기(@TestPropertySouce
사용)
yml 파일을 건드려도 테스트 파일로 제한하여 설정하면 협업에 영향은 없지만,
혹시 모를 경우를 대비하여 테스트 클래스에서 DB 설정 직접 넣는 방법을 택했다.
(이후 무수한 고난을 겪은 후 1번으로 돌아가 재구현 도전했으나.. 그마저도 같은 에러를 겪어 테스트코드 구현은 포기하기로 했다ㅠ)
@SpringBootTest
@AutoConfigureMockMvc
@Transactional
@TestPropertySource(properties = {
"spring.datasource.url=jdbc:h2:mem:testdb",
"spring.datasource.driver-class-name=org.h2.Driver",
"spring.datasource.username=sa",
"spring.datasource.password=",
"spring.jpa.hibernate.ddl-auto=create",
"spring.jpa.show-sql=true"
})
public class CommentApplicationTest {
...
}
다음과 같이 직접적으로 DB 설정을 했더니,
Cannot resolve class or package 'h2' 에러가 났다.
해당 에러는 H2 데이터베이스 라이브러리가 의존성에 없어서 생기는 에러라고 한다.
Spring Boot는 기본적으로 H2 DB를 지원하지만, build.gradle이나 pom.xml에 직접 추가해줘야 사용 가능하다.
build.gradle 에 의존성을 동료 분들에게 영향이 가지 않을 선에서 추가하기 위해 testImplementation
으로 추가하여 테스트 환경에서만 사용되도록 설정하였다.
dependencies {
testImplementation 'com.h2database:h2'
}
testImplementation
could not prepare statement [Syntax error in SQL statement "/* insert for org.example.twosixtagram.domain.user.entity.User
빌드 후 다시 테스트 코드를 돌리는데 구문 오류가 발생했다.
해당 에러의 원인은 다음과 같다.
user
라는 테이블 이름이 SQL 에서 예약어(reserved keyword) 라서, H2 에서는 insert into user
문이 구문 오류를 발생시키기 때문이다.
나는 아무래도 User 관련 파일들은 건들지 못하기 때문에 오류를 회피하는 방법인 후자를 택했다.
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
해당 구문을 @TestPropertySource
에 추가해줬다.
@TestPropertySource(properties = {
"spring.datasource.url=jdbc:h2:mem:testdb",
"spring.datasource.driver-class-name=org.h2.Driver",
"spring.datasource.username=sa",
"spring.datasource.password=",
"spring.jpa.hibernate.ddl-auto=create",
"spring.jpa.show-sql=true",
"spring.jpa.properties.hibernate.globally_quoted_identifiers=true" // 이거 추가!
})
구문을 추가함으로써 앞으로 Hibernate가 테이블/컬럼 이름을 DDL과 SQL 쿼리에서 자동으로 큰따옴표("user")로 감싸주게 되었다.
--> "user"
처럼 감싸주면 H2에서도 "user"
는 그냥 테이블 이름으로 인식되기 때문에 문제 없게 되는 것이다.
예약어 충돌 에러를 해결했더니 다음 난관에 봉착했다..
Table "USER" not found (this database is empty)
User
, NewsFeed
엔티티 모두 Comment 와 연관관계가 있어서 테스트에 필요한데,
Spring Boot 는 @SpringBootTest
실행 시
-> 해당 Entity 클래스가 컴포넌트 스캔 범위에 포함되어 있어야만 테이블을 자동 생성해주기 때문에 에러가 남
테스트 실행 시 User, NewsFeed 엔티티가 포함되도록 보장해야 한다.
@EntityScan(basePackages = "org.example.twosixtagram.domain") // 여기에 User, NewsFeed, Comment 다 포함되게
도메인 경로를 명시하였음에도 User 테이블이 만들어지지 않았다.
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@EnableJpaRepositories(basePackages = "org.example.twosixtagram.domain")
UserRepository
, NewsfeedRepository
등이 정상 주입되려면 @EnableJpaRepositories
이 필요할 수도 있다고 하여 추가했다.
계속 해서 같은 에러가 발생했다.
Table "USER" not found (this database is empty)
아무리 설정을 잘 해놔도 User 엔티티에 대한 테이블 자체가 생성되지 않고 있다.
@SpringBootTest
가 애플리케이션 전체를 로딩한다고 해도, EntityScan
만으로는 JPA 가 테이블을 생성하지 않기도 한다고 한다 ...
왜 ???
@SpringBootTest
는 Application
클래스에 의존해 전체 컨텍스트를 불러오는데,
해당 Application 클래스가 @SpringBootApplication
을 기준으로 스캔되지 않으면 Hibernate 가 entity 를 감지 못한다고 한다...
@SpringBootTest(classes = org.example.twosixtagram.TwoSixTagramApplication.class)
그럼에도 불구하고!!! 여전히 엔티티 테이블 생성이 되지 않았다.
User 엔티티를 건드릴 수 없을 때, schma.sql
로 테이블을 직접 만드는 방안도 있다고 했지만 ...
sql 파일을 추가하는 것보다, yml 에 테스트용으로 설정을 추가하는 것이 사이드 이펙트가 적어보여서 다시 초반으로 돌아가 설정을 다시 하기로 했다...
테스트 클래스에서 DB 설정 직접 넣기 방법 실패 ...
application.yml / application.properties 설정 추가 방법도 같은 이유로 실패..