-
Notifications
You must be signed in to change notification settings - Fork 2
test: TestContainer 적용 #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| spring: | ||
| jpa: | ||
| hibernate: | ||
| ddl-auto: create |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| package in.koreatech.koin; | ||
|
|
||
| import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; | ||
|
|
||
| import in.koreatech.koin.support.DBInitializer; | ||
| import io.restassured.RestAssured; | ||
| import org.junit.jupiter.api.BeforeEach; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.boot.test.context.SpringBootTest; | ||
| import org.springframework.boot.test.web.server.LocalServerPort; | ||
| import org.springframework.context.annotation.Import; | ||
| import org.springframework.test.context.ActiveProfiles; | ||
| import org.springframework.test.context.DynamicPropertyRegistry; | ||
| import org.springframework.test.context.DynamicPropertySource; | ||
| import org.testcontainers.containers.MySQLContainer; | ||
| import org.testcontainers.junit.jupiter.Container; | ||
|
|
||
| @SpringBootTest(webEnvironment = RANDOM_PORT) | ||
| @Import(DBInitializer.class) | ||
| @ActiveProfiles("test") | ||
| public abstract class AcceptanceTest { | ||
|
|
||
| private static final String ROOT = "test"; | ||
| private static final String ROOT_PASSWORD = "1234"; | ||
|
Comment on lines
+23
to
+24
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분은
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 위에서 한수에게 답변한 내용과 동일합니다~
해당 MySQL 컨테이너를 띄우는 부분은 오로지 testContainer에서 static하게 단 한번만 사용하므로 전역적으로 yml 파일로 선언하기보다는 작성해주신 대로 해당 코드에서만 사용하는게 어떨까 생각이 듭니다. 별도의 config 파일로 분리할 정도로 중요한 내용이 아니라고 생각되고, 반복되지 않는 작업을 불필요하게 분리하여 관리 요소가 늘어나는 것 같다 라는 의견입니다.
Comment on lines
+23
to
+24
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 설정이
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 넹 아무거나 넣어도 됩니다~! |
||
|
|
||
| @LocalServerPort | ||
| protected int port; | ||
|
|
||
| @Autowired | ||
| private DBInitializer dataInitializer; | ||
|
|
||
| @Container | ||
| protected static MySQLContainer container; | ||
|
|
||
| @DynamicPropertySource | ||
| private static void configureProperties(final DynamicPropertyRegistry registry) { | ||
| registry.add("spring.datasource.url", container::getJdbcUrl); | ||
| registry.add("spring.datasource.username", () -> ROOT); | ||
| registry.add("spring.datasource.password", () -> ROOT_PASSWORD); | ||
| } | ||
|
|
||
| static { | ||
| container = (MySQLContainer) new MySQLContainer("mysql:5.7.34") | ||
| .withDatabaseName("test") | ||
| .withUsername(ROOT) | ||
| .withPassword(ROOT_PASSWORD) | ||
| .withCommand("--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci"); | ||
| container.start(); | ||
| } | ||
|
|
||
| @BeforeEach | ||
| void delete() { | ||
| if (RestAssured.port == RestAssured.UNDEFINED_PORT) { | ||
| RestAssured.port = port; | ||
| } | ||
| dataInitializer.clear(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| package in.koreatech.koin.support; | ||
|
|
||
| import jakarta.persistence.EntityManager; | ||
| import jakarta.persistence.PersistenceContext; | ||
| import java.sql.ResultSet; | ||
| import java.sql.Statement; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import javax.sql.DataSource; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.boot.test.context.TestComponent; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| @TestComponent | ||
| public class DBInitializer { | ||
|
|
||
| private static final int OFF = 0; | ||
| private static final int ON = 1; | ||
| private static final int COLUMN_INDEX = 1; | ||
|
|
||
| private final List<String> tableNames = new ArrayList<>(); | ||
|
|
||
| @Autowired | ||
| private DataSource dataSource; | ||
|
|
||
| @PersistenceContext | ||
| private EntityManager entityManager; | ||
|
|
||
| private void findDatabaseTableNames() { | ||
| try (final Statement statement = dataSource.getConnection().createStatement()) { | ||
| ResultSet resultSet = statement.executeQuery("SHOW TABLES"); | ||
| while (resultSet.next()) { | ||
| final String tableName = resultSet.getString(COLUMN_INDEX); | ||
| tableNames.add(tableName); | ||
| } | ||
| } catch (Exception e) { | ||
| e.printStackTrace(); | ||
| } | ||
| } | ||
|
|
||
| private void truncate() { | ||
| setForeignKeyCheck(OFF); | ||
| for (String tableName : tableNames) { | ||
| entityManager.createNativeQuery(String.format("TRUNCATE TABLE %s", tableName)).executeUpdate(); | ||
| } | ||
| setForeignKeyCheck(ON); | ||
| } | ||
|
|
||
| private void setForeignKeyCheck(int mode) { | ||
| entityManager.createNativeQuery(String.format("SET FOREIGN_KEY_CHECKS = %d", mode)).executeUpdate(); | ||
| } | ||
|
|
||
| @Transactional | ||
| public void clear() { | ||
| if (tableNames.isEmpty()) { | ||
| findDatabaseTableNames(); | ||
| } | ||
| entityManager.clear(); | ||
| truncate(); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
설정을 클래스로 따로 분리해서, 인수 테스트를 생성할 때는 해당 클래스를 상속만 받으면 되니까 편리하고 보기 좋은 것 같습니다!
이름은 왜
Acceptance인가요?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
인수테스트에 해당 클래스를 상속받게 만들고자했습니다~!
용어는
인수 검사(acceptance testing)에서 따왔습니다