뉴스피드 프로젝트 트러블슈팅 (1) - 테스트코드

ssongyi·2025년 4월 9일
0
post-thumbnail

뉴스피드에서 댓글 파트를 맡았다.
해당 파트는 유저, 뉴스피드 작업이 완료되어야지만 실질적으로 테스트가 가능하다.
그래서 테스트 어플리케이션을 만들어서 돌려보고자 했다.
굉장히 많은 에러를 접했는데.. 천천히 몇개만 풀어보겠다.

테스트용 생성자 만들기

@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);

H2나 MySQL 등 데이터베이스 설정 누락

DataSourceAutoConfiguration.PooledDataSourceConfiguration#jdbcConnectionDetails matched:
- @ConditionalOnMissingBean (types: org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails; SearchStrategy: all) did not find any beans (OnBeanCondition)

테스트코드를 실행했더니 해당 메시지가 출력됐다.
이것은 Spring BootConditions EvaluationReport 이며, 어떤 자동 설정(AutoConfiguration) 이 활성화되었는지 알려주는 디버깅용 로그라고 한다.

해당 메시지가 의미하는 바는,
H2나 MySQL 등 데이터베이스 설정 누락되어 있어서, DataSource(JDBC 연결 정보) 를 못 찾고 있다는 뜻이라고 한다.

해결 방법으로는 두 가지가 있다.
1. application.yml 또는 application.properties 에 DB 설정 추가
2. 테스트 클래스에서 DB 설정 직접 넣기(@TestPropertySouce 사용)

yml 파일을 건드려도 테스트 파일로 제한하여 설정하면 협업에 영향은 없지만,
혹시 모를 경우를 대비하여 테스트 클래스에서 DB 설정 직접 넣는 방법을 택했다.
(이후 무수한 고난을 겪은 후 1번으로 돌아가 재구현 도전했으나.. 그마저도 같은 에러를 겪어 테스트코드 구현은 포기하기로 했다ㅠ)

테스트 클래스에 DB 설정 직접 넣기 --> h2 의존성 에러

@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에 직접 추가해줘야 사용 가능하다.

h2 의존성 해결방안 (testImplementation)

build.gradle 에 의존성을 동료 분들에게 영향이 가지 않을 선에서 추가하기 위해 testImplementation 으로 추가하여 테스트 환경에서만 사용되도록 설정하였다.

dependencies {
    testImplementation 'com.h2database:h2'
}

testImplementation

  • 운영 코드에 전혀 영향 X
  • 이 설정은 src/test 에서 실행되는 코드에서만 H2 를 사용할 수 있게 함
  • 빌드 후 실제 배포에는 포함되지 X (협업자 영향 X)
  • Spring Boot는 H2를 테스트용 DB의 기본값으로 지원
  • 대부분의 협업/팀 프로젝트에서도 테스트 전용 DB로 사용
  • 테스트 실행 후 DB는 자동 삭제됨

user 테이블 예약어 구문 오류 (Syntax error)

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 문이 구문 오류를 발생시키기 때문이다.

해결방안

  1. user 테이블 이름 변경함으로써 예약어 충돌 피하기 (ex. users)
  2. H2 가 'user' 테이블 이름을 이해하도록 강제 설정

나는 아무래도 User 관련 파일들은 건들지 못하기 때문에 오류를 회피하는 방법인 후자를 택했다.

Hibernate 가 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"는 그냥 테이블 이름으로 인식되기 때문에 문제 없게 되는 것이다.


User 엔티티에 해당하는 테이블 자체가 생성되지 않음 오류

예약어 충돌 에러를 해결했더니 다음 난관에 봉착했다..

Table "USER" not found (this database is empty)

원인

User, NewsFeed 엔티티 모두 Comment 와 연관관계가 있어서 테스트에 필요한데,
Spring Boot 는 @SpringBootTest 실행 시
-> 해당 Entity 클래스가 컴포넌트 스캔 범위에 포함되어 있어야만 테이블을 자동 생성해주기 때문에 에러가 남

해결방안

테스트 실행 시 User, NewsFeed 엔티티가 포함되도록 보장해야 한다.

(첫번째시도) @EntityScan 으로 도메인 경로 명시

@EntityScan(basePackages = "org.example.twosixtagram.domain") // 여기에 User, NewsFeed, Comment 다 포함되게

도메인 경로를 명시하였음에도 User 테이블이 만들어지지 않았다.

(두번째시도) @EnableJpaRepositories 추가

  • @EntityScan 도 잘 들어갔고
  • ddl-auto=create 설정도 되어 있는데
  • 테이블이 생성되지 않았다는 것은 Hibernate 가 Entity 를 인식했지만 실제로 테이블 생성을 하지 않았거나, Entity 를 등록하지 못한 것이다.
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@EnableJpaRepositories(basePackages = "org.example.twosixtagram.domain")

UserRepository, NewsfeedRepository 등이 정상 주입되려면 @EnableJpaRepositories 이 필요할 수도 있다고 하여 추가했다.

(세번째시도) classes 명시해서 테스트에 전체 설정 강제 로딩

계속 해서 같은 에러가 발생했다.

Table "USER" not found (this database is empty)

아무리 설정을 잘 해놔도 User 엔티티에 대한 테이블 자체가 생성되지 않고 있다.

@SpringBootTest 가 애플리케이션 전체를 로딩한다고 해도, EntityScan 만으로는 JPA 가 테이블을 생성하지 않기도 한다고 한다 ...

왜 ???

@SpringBootTestApplication 클래스에 의존해 전체 컨텍스트를 불러오는데,
해당 Application 클래스가 @SpringBootApplication 을 기준으로 스캔되지 않으면 Hibernate 가 entity 를 감지 못한다고 한다...

@SpringBootTest(classes = org.example.twosixtagram.TwoSixTagramApplication.class)

그럼에도 불구하고!!! 여전히 엔티티 테이블 생성이 되지 않았다.
User 엔티티를 건드릴 수 없을 때, schma.sql 로 테이블을 직접 만드는 방안도 있다고 했지만 ...

sql 파일을 추가하는 것보다, yml 에 테스트용으로 설정을 추가하는 것이 사이드 이펙트가 적어보여서 다시 초반으로 돌아가 설정을 다시 하기로 했다...

테스트 클래스에서 DB 설정 직접 넣기 방법 실패 ...
application.yml / application.properties 설정 추가 방법도 같은 이유로 실패..

0개의 댓글