-
Notifications
You must be signed in to change notification settings - Fork 4
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
기존 테스트 환경 TestContainers로 리팩토링 #434
Conversation
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.
코드 맛있게 읽었습니다!
몇가지 궁금한점 남겨놨는데 확인해주세요~
@@ -82,4 +82,4 @@ create table if not exists `yozm-cafe`.menu_board ( | |||
CONSTRAINT menu_board_cafe_id | |||
foreign key (cafe_id) references cafe (id) | |||
ON DELETE CASCADE | |||
); | |||
); |
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.
저기.. 선생님 죄송하지만 여기 개행하나만 추가해주시겠어요...? flywayPR merge되면서 개행이 사라진 듯 하네요 ㅠ
/** | ||
* Application Context들이 필요할 때 상속하면 됩니다. | ||
* Repository, Service 레이어 통합 테스트용으로 쓰면 됩니다. | ||
*/ | ||
@SpringBootTest |
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.
감사합니다. 잘먹겠습니다.
@DynamicPropertySource | ||
static void configureProperties(final DynamicPropertyRegistry registry) { | ||
registry.add("spring.datasource.url", container::getJdbcUrl); | ||
registry.add("spring.datasource.username", () -> "root"); | ||
registry.add("spring.datasource.password", () -> "test"); | ||
} | ||
|
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.
이런 방식으로도 properties를 동적으로 매핑해줄수가 있네요!
음 근데 궁금한게 있습니다.
datasource.url
같은 경우는 테스트컨테이너가 매번 랜덤한 포트를 사용하기에 이렇게 동적으로 바인딩 해주는 것이 이해가 되는데,
username
과 password
도 동적으로 매핑해줄 필요가 있나요??
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.
application-test.properties
에 username
과 password
추가해주면 되는거 아닌가 싶어서요~
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.
테스트 컨테이너의 루트 비밀번호를 윗 줄에서 test로 관리하고 있어서 여기에서 매핑을 했습니다!
static {
container = (MySQLContainer) new MySQLContainer("mysql:8.0")
.withDatabaseName("yozm-cafe")
.withEnv("MYSQL_ROOT_PASSWORD", ROOT_PASSWORD)
.withReuse(true);
container.start();
}
@DynamicPropertySource
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);
}
위와 같이 하나의 상수로 관리할 수 있도록 적용했습니다!
properties
에 적용해도 되지만 루트 비밀번호를 테스트 컨테이너 생성할 때 설정해줘야 하기 때문에 위와 같이 했습니다.
@Autowired | ||
private DataInitializer dataInitializer; | ||
|
||
@BeforeEach | ||
void delete() { | ||
dataInitializer.deleteAll(); | ||
} |
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.
필드 변수가 왜 여기..?
서로 연관있는 애들끼리 묶어 놓으려했던 의도 같아요. 맞을까요?
근데 delete()
method 에서 dataInitializer
가 사용되는 걸보고
엥 이런게 있었나 하면서 파일 최상단으로 스크롤을 올리다가 위 필드변수를 보게되었어요.
혹시 이게 제가 모르는 컨벤션일까요??
아니라면, 관습적으로 사용하는 컨벤션은 따르는게 가독성이 좋지 않을까 싶어요.
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.
헉 프리코스 때보다 못해진 제 자신이네요ㅠㅠ
수정했습니다!
@DataJpaTest | ||
@AutoConfigureTestDatabase(replace = Replace.NONE) | ||
class CafeRepositoryTest { | ||
class CafeRepositoryTest extends BaseTest { |
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.
이렇게 되면 RepositoryTest 도 @SpringBootTest로 돌아가겠네요..
delete()를 통해서 테스트 격리는 되겠지만, 테스트 속도에 유의미한 차이는 없던가요??
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.
단일 클래스 전체 테스트할 때는 모든 ApplicationContext
를 띄우기 때문에 더 느려집니다.
하지만 빌드를 하거나 전체 테스트들을 모두 돌릴 때는 ApplicationContext
를 재사용하기 때문에 속도 차이가 없습니다!
단일 클래스 테스트 속도 차이가 크다면, @SpringBootTest
대신 다른 어노테이션을 붙인 새로운 BaseTest
를 만들어 쓰면 좋을 것 같습니다.
레이어별로 BaseTest
가 생겨서 헷갈릴 수 있을 것 같아서 지금의 구조로 했습니다.
바꾸는 것이 좋을까요??!
assertSoftly(softAssertions -> { | ||
assertThat(cafes).hasSize(5); | ||
assertThat(cafes).containsExactlyInAnyOrder(cafe1, cafe2, cafe3, cafe4, cafe5); | ||
}); | ||
} |
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.
틈새 리팩토링 ㄷㄷ;; 감사합니다.
private void init() { | ||
try (final Statement statement = dataSource.getConnection().createStatement()) { | ||
final ResultSet resultSet = statement.executeQuery("SHOW TABLES "); | ||
|
||
while (resultSet.next()) { | ||
final String tableName = resultSet.getString(FIRST_COLUMN); | ||
if (tableName.contains(FLYWAY)) { | ||
continue; | ||
} | ||
|
||
deleteDMLs.add("TRUNCATE " + tableName); | ||
} | ||
} catch (Exception e) { | ||
e.printStackTrace(); | ||
} | ||
} |
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.
이 부분 이해가 잘 안되는데... 내일 직접 대면으로 물어볼게요..!
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.
- DB와 연결된
DataSource
를 주입 받아서 사용합니다. - 거기로
SHOW TABLES;
SQL을 날려서ResultSet
을 받습니다. - 결과는 테이블 이름들이고, 그 앞에 각각
Truncate
를 붙여서 전체 테이블에 대한 Truncate 문을 만듭니다. 이때flyway
히스토리 테이블까지 삭제하면 매번 스키마가 적용되므로 warning이 로그에 뜨길래 제외해줬습니다.
위와 같이 한 이유는 지금까지 truncate.sql
을 직접 작성해서 사용했는데 테이블을 추가하고 빠트리는 경우가 있어서 그렇습니다.
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.
테스트 컨테이너 맛있네요
continue; | ||
} | ||
|
||
deleteDMLs.add("TRUNCATE " + tableName); |
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.
오 flyway 테이블을 제외한 테이블들을 조회해와서 truncate를 이렇게 하는군요. 짱이네요
@ActiveProfiles("test") | ||
public abstract class BaseTest { | ||
|
||
@Container |
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.
아래에서 직접 container.start() 하기에 @Container
은 붙이지 않아도 될 것 같아요!
https://java.testcontainers.org/test_framework_integration/junit_5/
container = (MySQLContainer) new MySQLContainer("mysql:8.0") | ||
.withDatabaseName("yozm-cafe") | ||
.withEnv("MYSQL_ROOT_PASSWORD", "test") | ||
.withReuse(true); |
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.
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.
private final 에서도 재사용하는 옵션인가보군요!
적용되지 않는 거 보고 제거했습니다.
재사용되는 이유는 static 필드로 써서 다시 띄우지 않습니다.
#️⃣ 연관된 이슈
📝 작업 내용
DataInitializer
구현BaseTest
구현