@DataJpaTest๋ฅผ ์ด์ฉํ Repository ํ
์คํธ ์ค ๋ณธ ์ดํ๋ฆฌ์ผ์ด์
์คํ์์ ๋ฐ์ํ์ง ์๋ DDL์์ ์์ธ๊ฐ ๋ฐ์ํ๋ค. H2 ↔๏ธ MySQL ๋ฌธ๋ฒ ์ฐจ์ด๋ก ์ธํด ํ
์ด๋ธ์ด ์ ๋๋ก ์์ฑ๋์ง ์๋ ๊ฒ์ผ๋ก ๋ณด์ฌ์ application-test.properties
๋ฅผ ๊ณ์ ์์ ํ์ง๋ง ํด๊ฒฐ๋์ง ์์๋ค. ๋ฌธ๋, ์ง๋ ๋ฒ์๋ @DataJpaTest
ํ
์คํธ์์ ๋ฐ์ํ๋ ์๋ฌ๋ฅผ @AutoConfigureTestDatabase
์ผ๋ก ํด๊ฒฐํ ๊ธฐ์ต์ด๋์ ์๋ํ์๊ณ ํด๊ฒฐ๋์๋ค. ๊ทธ๋๋ ๋๋ฒ๊น
๊ณผ์ ๊ธฐ๋ก์ ๋ฏธ๋ค๋๊ณ ์์๋๋ฐ, ์ด ์ฐธ์ ๋ธ๋ก๊น
ํ๊ณ ์ฅ๊ธฐ ๊ธฐ์ต์ผ๋ก ๊ฐ๋ณด์.
๋ฌธ์ ๋ถ์
์๋ํ ๋๋ง๋ค ๋ค์ํ ์์ธ๊ฐ ๋ฐ์ํ๊ณ ์ธํฐ๋ท์๋ ๋ค์ํ ์์ธ ์ผ์ด์ค๊ฐ ์๋๋ฐ, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์ ๋ฌธ์ ์ด๊ฑฐ๋ DDL ํน์ SQL ๋ฌธ๋ฒ ์ค๋ฅ๋ค. ๊ณตํต์ ์ผ๋ก DataSoruce๋ก ์ธํด ๋ฐ์ํ ๊ฒ์ธ๋ฐ, ๋ณธ ์ดํ๋ฆฌ์ผ์ด์
์ ์ ์์ ์ผ๋ก ๋ฌ๋๋ฐ, ์ ํ
์คํธํ ๋๋ง ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋๊ฑธ๊น? @DataJpaTest
๋ฅผ ์์ธํ ์ดํด๋ณด์
CommandAcceptanceException: Error executing DDL - ... (this database is empty)
JdbcSQLSyntaxErrorException: Syntax error in SQL statement ... expected "identifier"
/**
* Annotation for a JPA test that focuses <strong>only</strong> on JPA components.
* <p>
* Using this annotation will disable full auto-configuration and instead apply only
* configuration relevant to JPA tests. * <p>
* By default, tests annotated with {@code @DataJpaTest} are transactional and roll back
* at the end of each test. They also use an embedded in-memory database (replacing any * explicit or usually auto-configured DataSource). The * {@link AutoConfigureTestDatabase @AutoConfigureTestDatabase} annotation can be used to
* override these settings. * <p>
* SQL queries are logged by default by setting the {@code spring.jpa.show-sql} property
* to {@code true}. This can be disabled using the {@link DataJpaTest#showSql() showSql}
* attribute. * <p>
* If you are looking to load your full application configuration, but use an embedded
* database, you should consider {@link SpringBootTest @SpringBootTest} combined with
* {@link AutoConfigureTestDatabase @AutoConfigureTestDatabase} rather than this
* annotation. * <p>
* When using JUnit 4, this annotation should be used in combination with
* {@code @RunWith(SpringRunner.class)}.
* * @author Phillip Webb
* @author Artsiom Yudovin
* @author Scott Frederick
* @since 1.4.0
* @see AutoConfigureDataJpa
* @see AutoConfigureTestDatabase
* @see AutoConfigureTestEntityManager
* @see AutoConfigureCache
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@BootstrapWith(DataJpaTestContextBootstrapper.class)
@ExtendWith(SpringExtension.class)
@OverrideAutoConfiguration(enabled = false)
@TypeExcludeFilters(DataJpaTypeExcludeFilter.class)
@Transactional
@AutoConfigureCache
@AutoConfigureDataJpa
@AutoConfigureTestDatabase
@AutoConfigureTestEntityManager
@ImportAutoConfiguration
public @interface DataJpaTest {
// ...
}
์ฃผ์์๋ ์ ์ค๋ช
๋์ด ์๋ @DataJpaTest
์ ํน์ฑ์ ๋ค์๊ณผ ๊ฐ๋ค.
- full application context๋ฅผ ๋ก๋ํ์ง ์๊ณ JPA ํ ์คํธ์ ๊ด๋ จ๋ configuration๋ง ํ์ฑํํ๋ ํ ์คํธ ์ด๋ ธํ ์ด์
- Repository ๊ณ์ธต์ ๋ํ ๊ฒฉ๋ฆฌ๋ ํ ์ฝ ํ๊ฒฝ์ ์ค์ ํ๋๋ฐ ์ ์ฉ
- ์๋ฒ ๋๋ ์ธ๋ฉ๋ชจ๋ฆฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉ
์ดํ๋ฆฌ์ผ์ด์
์คํํ ๋๋ H2 ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ๊ณ ์๋๋ฐ, ๋ญ๊ฐ ๋ค๋ฅธ๊ฑธ๊น? The @AutoConfigureTestDatabase annotation can be used to override these settings.
๋ผ๊ณ ํ๋, @AutoConfigureTestDatabase
์ ์ดํด๋ณด์.
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@ImportAutoConfiguration
@PropertyMapping("spring.test.database")
public @interface AutoConfigureTestDatabase {
/**
* Determines what type of existing DataSource bean can be replaced. * @return the type of existing DataSource to replace
*/ @PropertyMapping(skip = SkipPropertyMapping.ON_DEFAULT_VALUE)
Replace replace() default Replace.ANY;
/**
* The type of connection to be established when {@link #replace() replacing} the
* DataSource. By default, will attempt to detect the connection based on the * classpath. * @return the type of connection to use
*/
EmbeddedDatabaseConnection connection() default EmbeddedDatabaseConnection.NONE;
/**
* What the test database can replace.
* */
enum Replace {
/**
* Replace the DataSource bean whether it was auto-configured or manually defined.
* */
ANY,
/**
* Only replace the DataSource if it was auto-configured.
* */
AUTO_CONFIGURED,
/**
* Don't replace the application default DataSource.
* */
NONE
}
}
@PropertyMapping("spring.test.database")
์ ํตํด ๊ฐ์ ์ค์ ํ ์ ์์ง๋ง, application property์์ ๋ฐ๋ก ์ค์ ํ ๊ฐ์ด ์์ผ๋ ๋ํดํธ ์ค์ ์ ๋ฐ๋ฅธ๋ค. replace ๊ธฐ๋ณธ ์ ๋ต์ ANY๋ ์๋ฒ ๋๋ ๋ฌด์กฐ๊ฑด ์ธ๋ฉ๋ชจ๋ฆฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ DataSource๋ก ์ค์ ํ๊ณ , connection ๊ธฐ๋ณธ ์ ๋ต์ NONE์ด์ง๋ง EmbeddedDatabaseConnection
, TestDatabaseAutoConfiguration
๋ฑ์ ํตํด ClassLoader๊ธฐ๋ฐ์ผ๋ก ์ ํฉํ ์ปค๋ฅ์
์ ์ ๊ณตํ๋ค. ๋์ ๊ฒฝ์ฐ๋ H2 ์ปค๋ฅ์
์ผ๋ก ์ค์ ๋๋ ๊ฒ์ ๋ก๊ทธ์์ ํ์ธํ ์ ์์๋ค.
์์ธ ํ์
์ด? ์ดํ๋ฆฌ์ผ์ด์
ํ๊ฒฝ๊ณผ ๋์ผํ H2์ธ๋ฐ ์ ์๋์ง? ๋ผ๊ณ ์๊ฐํ๋ค๋ฉด, ๋น์ ์ ๋๋ฒ๊น
๊ตฌ๋ ํ
์ด์ ๋น ์ง๊ฒ ๋ ๊ฒ์ด๋ค.... ์ด ์ค์ ์ EmbeddedDatabaseConnection
์ ์ค์ ๋ ๊ธฐ๋ณธ H2 url์ ๋๋คํ ์ ๋ํฌ UUID๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ด๋ฆ์ผ๋ก ์๋ ์์ฑ๋ ์๋ฒ ๋๋ ์ธ๋ฉ๋ชจ๋ฆฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ธ๋ฐ, ;MODE=MYSQL;
์ด ์๋ค!! ์ด๊ธฐ ์ดํ๋ฆฌ์ผ์ด์
์ธํ
์ดํ ์ ๊ฒฝ์ฐ์ง ์์ ๊น๋จน์์ ํ
๋ฐ, H2์ MySQL์ ์ ์ฌํ์ง๋ง ๋ค๋ฅธ ๋ฌธ๋ฒ์ด ์กด์ฌ(ํนํ DDL)ํ๊ธฐ ๋๋ฌธ์ MySQL ๋ชจ๋๋ก DataSource๋ฅผ ์ค์ ํด์ผ๋ง ํ๋ค.
public enum EmbeddedDatabaseConnection {
/**
* No Connection.
* */
NONE(null),
/**
* H2 Database Connection.
* */
H2("jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"),
/**
* Derby Database Connection.
* */
DERBY("jdbc:derby:memory:%s;create=true"),
/**
* HSQL Database Connection. * @since 2.4.0
*/
HSQLDB("org.hsqldb.jdbcDriver", "jdbc:hsqldb:mem:%s");
// ...
}
ํด๊ฒฐ ๋ฐฉ์
2๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ํด๊ฒฐํ ์ ์๋๋ฐ
spring.jpa.properties.hibernate.dialect
์ ๊ธฐ๋ณธ ๊ฐ ํน์ H2Dialect๋ก ์ค์ ํ๋ค.AutoConfigureTestDatabase
์Replace
์ ๋ต์NONE
์ผ๋ก ์ค์ ํ๋ค.
์ฒ์๋ถํฐ ๋ก์ปฌ์์ H2๋ก ์ด ์ฌ๋์ด๋ผ๋ฉด 1๋ฒ์ ํํ๋ฉด ๋์ง๋ง, ์ผ๋ฐ์ ์ผ๋ก ํ๋ก๋์ ํ๊ฒฝ์ ๋ง์ถ๊ธฐ ์ํด MySQL ๋ชจ๋๋ก ์ฌ์ฉํ๊ณ ์๋ ์ฌ๋๋ ๋ง์ ๊ฒ์ด๋ค. ํนํ ๋๋ ๋ ์ง์ ๊ด๋ จ๋ ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋๋ฐ, H2์ MySQL์์ ์ง์ํ๋ ๋ ์ง ํจ์๊ฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ 1๋ฒ์ ์ฌ์ฉํ ์ ์๋ค. 1๋ฒ์ ์ฌ์ฉํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
๋ฐ๋ผ์ ๋ค์๊ณผ ๊ฐ์ด ์ด๋ ธํ ์ด์ ์ ํตํด Replace ์ ๋ต์ NONE์ผ๋ก ์ค์ ํ๋ฉด, properties์์ ์ค์ ํ DataSource๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ ์ ์๋ค.
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@ActiveProfiles("test")
class MemberPostRepositoryCustomTest {
// ...
}
์์ธ๋ช ๊ณผ Caused by ์ ์ ํตํด์๋ ์์ธ์ ์ ์ ์๋ ๋ฌธ์ ์๋ค. ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ ๋ฅผ ์ถ์ธกํ๊ณ ๊ตฌ๊ธ๋ง๊ณผ ํ๋ ์์ํฌ ์ฝ๋๋ฅผ ๋ถ์ํจ์ผ๋ก์จ ํด๊ฒฐํ ์ ์์๋๋ฐ, ์ด๊ฒ ์ง์ง ์ด์์ ์ธ ๋๋ฒ๊น ๊ฐ์์ ๋ฟ๋ฏํ๋ค. ๋ธ๋ก๊น ์๋ ๊ฝค ๋ง์ ์๊ฐ์ด ๋ค์๋๋ฐ, ๊ฒฐ๊ตญ์ ๊ธฐ๋ก์ด ๋ค ๋จ๋ ๊ฒ ๊ฐ์ผ๋ ์ด์ฌํ ํด๋ด์ผ๊ฒ ๋ค.