
스프링 부트와 AWS로 혼자 구현하는 웹 서비스를 혼자 따라하면서 공부하는 중인데, JPA repository를 테스트하다가 아래와 같은 에러가 났다.
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "
    CREATE TABLE POST (
       ID BIGINT NOT NULL AUTO_INCREMENT,
        AUTHOR VARCHAR(255),
        CONTENT VARCHAR(255) NOT NULL,
        TITLE VARCHAR(500) NOT NULL,
        PRIMARY KEY (ID)
    ) ENGINE=[*]INNODB"; expected "identifier"; SQL statement:@ExtendWith(SpringExtension.class)
@DataJpaTest
public class PostRepositoryTest {
    @Autowired
    PostRepository postRepository;
    @Test
    public void 게시글저장_불러오기() throws Exception {
        // given
        String title = "테스트 게시글";
        String content = "테스트 본문";
        String author = "test_author@gmail.com";
        postRepository.save(Post.builder()
                .title(title)
                .content(content)
                .author(author)
                .build());
        // when
        List<Post> postList = postRepository.findAll();
        // then
        assertThat(postList.size()).isEqualTo(1);
        Post post = postList.get(0);
        assertThat(post.getTitle()).isEqualTo(title);
        assertThat(post.getContent()).isEqualTo(content);
        assertThat(post.getAuthor()).isEqualTo(author);
    }
}간단한 Post 객체 하나 만들어서 저장하고, 조회하는 테스트였는데, 이걸 실행하니까 에러가 났다.
# sql 보기
spring.jpa.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
# h2 문법을 mysql로 변경
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
# 테이블 자동생성
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=updateH2 in-memory 데이터베이스로 간단하게 테스트를 하는 중이었기 때문에 dialect만 지정해주고 다른 구체적인 설정은 하지 않았다. 근데 저 MySQL5InnoDBDialect만 설정하면 에러가 터졌다.
에러 메세지에서 expected identifier.. 어쩌구 하길래, 예약어가 잘못 사용되었거나, h2 ↔ MySQL 문법 간 변환에 오류가 있었구나 싶었다. 그래서 관련 해결책을 구글링하고 적용했는데, 계속 똑같은 에러 메세지만 떴다.
우선, config에 아래 것들을 추가했다.
spring.datasource.url=jdbc:h2:~/test;MODE=MySQL;DATABASE_TO_LOWER=TRUEMySQL 모드로 지정하는 파라미터를 url에 지정해줬다. 소용없었다.
spring.jpa.properties.hibernate.globally_quoted_identifiers=true예약어를 quoted 처리하기 위해 자동으로 작은 따옴표를 붙여 주는 설정을 추가했다. 소용없었다.
에러 메세지는 예약어 관련이라고 했는데, JPA, MySQL, H2 문서를 뒤져봐도 모든 필드와 테이블 이름은 예약어가 아니었다. 한 시간동안 구글링을 더 해봐도 에러 메세지조차 변하지 않고 해결이 안돼서 겁나 짱났다.
혹시나 하면서 테스트 클래스의 @DataJpaTest 어노테이션을 @SpringBootTest로 변경해봤다.
@ExtendWith(SpringExtension.class)
@SpringBootTest
public class PostRepositoryTest {
	// ...
}    그랬더니 테스트가 통과했다..^^ 테이블도 잘 생성되고 조회도 잘 됐다..
사실 이 코드 작성하기 전에 @SpringBootTest와 @DataJpaTest의 차이점을 알아 보려다가~~ 넘 내용이 방대하고 복잡해보여서 일단 책부터 마무리하려고 했다. 근데 역시 대충대충 넘어가려다가 피보는 건 미래의 나인가보다...^^ 제때제때 모르는 것들 제대로 알고 넘어가자는 교훈을 얻었다....ㅎ...두 어노테이션의 차이는 여기에 정리했다.
암튼 그래서 @DataJpaTest와 @SpringBootTest의 차이점을 공부하면서, @DataJpaTest를 썼을 때 왜 제대로 작동하지 않는지 알아봤다. 결론적으로, @DataJpaTest의 @AutoConfigureTestDatabase가 config에 있는 H2 DB가 아닌, EmbeddedDatabaseConnection에 설정된 임시의 H2 DB를 호출해서 문제가 발생한 것이었다. 이 때 H2의 url은 
"jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE", (url) -> url.contains(":h2:mem")이렇게 설정되어 있다. 여기에 MODE=MySQL이 없어서 MySQL 문법으로 쿼리를 날리면 오류가 발생한 것이다.
application.properties에 아래 설정을 추가해야 한다.spring.datasource.url=jdbc:h2:~/dbname;MODE=MySQL;DATABASE_TO_LOWER=TRUE
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect@DataJpaTest를 진행하려면, @AutoConfigureTestDatabase를 replace=NONE으로 변경해야 한다.@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class SomeRepositoryTest {
	// ...
}끝
와.. 도움 많이 받았습니다 감사합니다!