스프링 부트와 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=update
H2 in-memory 데이터베이스로 간단하게 테스트를 하는 중이었기 때문에 dialect만 지정해주고 다른 구체적인 설정은 하지 않았다. 근데 저 MySQL5InnoDBDialect
만 설정하면 에러가 터졌다.
에러 메세지에서 expected identifier..
어쩌구 하길래, 예약어가 잘못 사용되었거나, h2 ↔ MySQL 문법 간 변환에 오류가 있었구나 싶었다. 그래서 관련 해결책을 구글링하고 적용했는데, 계속 똑같은 에러 메세지만 떴다.
우선, config에 아래 것들을 추가했다.
spring.datasource.url=jdbc:h2:~/test;MODE=MySQL;DATABASE_TO_LOWER=TRUE
MySQL 모드로 지정하는 파라미터를 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 {
// ...
}
끝
와.. 도움 많이 받았습니다 감사합니다!