test container / testcontainer / 스프링에서 / 스프링부트 / springboot / 스프링
spring에서 test container 사용시간 단축하기
test container 를 이용해서 test 를 하면, container 를 load 하는 시간이 오래걸린다. 개인적으로 ssd 가 아닌 hdd 에서 동작하도록 해서 그런지 더 실행시간이 오래걸렸다.
그래서 test 를 자주 하려면, 최대한 test container 의 실행을 줄이는 것이 좋다. 즉, 덜 자주 unload , load 를 하는 것이 낫다.
container 를 1번만 실행
Testcontainer 를 사용하면 test class에 @Testcontainers
를 사용하게 된다. 이것은 매 class마다 container 를 실행하게 된다.
대체로 test container 를 이용해서 test 를 하면, container 를 load 하는 시간이 오래걸린다. 개인적으로 ssd 가 아닌 hdd 에서 동작하도록 해서 그런지 더 실행시간이 오래걸렸다.
때문에, test 를 자주 하려면, 최대한 test container 의 실행을 줄이는 것이 좋다. 즉, 덜 자주 unload , load 를 하는 것이 낫다.
그래서 이것을 우리는 이것을 전체 test 에서 1번만 실행하게 할 것이다.
위 글에도 나와 있지만 static variable 에 할당하는 것으로 container 의 생성을 1번으로 만든다.
datasource 의 설정
이것은 ApplicationContextInitializer
를 이용한다.
특정 profile 에서는 현재 띄워져있는 container 를 사용하도록 한다
testcontainer를 부하를 줄이려 1번만 load 한다고 해도, TDD 등을 할때는 속도가 엄청 느리다. 계속 unload/load 가 이뤄지기 때문에 빠른 개발이 어렵다.
그래서 build 시점에는 testcontainer 를 사용해서 test 를 하지만, 개발을 할때는 현재 띄워져 있는 container에 접속해서 test 할 수 있도록 했다.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(initializers = TestcontainersInitializer.class)
class FishApplicationTests {
}
...
public class TestcontainersInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
private static final String MIGRATION_LOCATION = "filesystem:db/migration";
public static final MariaDBContainer<?> mariaDB = new MariaDBContainer<>("mariadb:10.6")
.withDatabaseName("myapp")
.withUsername("myapp-user")
.withUrlParam("useBulkStmts", "false")
.withPassword("strong-password")
.withReuse(true);
public static final LocalStackContainer localStack = new LocalStackContainer(
DockerImageName.parse("localstack/localstack"))
.withServices(LocalStackContainer.Service.S3)
.withReuse(true);
public static final KafkaContainer kafka = new KafkaContainer(
DockerImageName.parse("confluentinc/cp-kafka:7.5.0"))
.withReuse(true);
/*
* Static block runs before Spring Boot starts the application context.
*/
@Override
public void initialize(@NotNull ConfigurableApplicationContext ctx) {
// if system.property active profile is test, do not start containers
final String EXCLUDE_PROFILE = "testnocontainer";
var activeProfiles = ctx.getEnvironment().getActiveProfiles();
if (activeProfiles.length <= 0 || !activeProfiles[0].equals(EXCLUDE_PROFILE)) {
// if active profile is NOT 'testnocontainer'
// 만약 여러개의 test class 를 실행하면 이부분은 당연히 여러번 실행된다. 하지만 괜찮다.
// static 이라서 여러번 실행되지 않았다.
/**
* This routine runs multiple times, but due to the use of the static variables,
* it only works once
*/
/*
* deepStart() is used to start containers in parallel.
*/
Startables.deepStart(mariaDB, localStack, kafka).join();
runMigrations(); // run flyway
// 여기를 실행하지 않는 profile 은 application.xml 의 datasource 쪽을 바라보게 된다.
// 그러므로 datasource setting 을 해놔야 한다.
TestPropertyValues.of("spring.datasource.url=" + mariaDB.getJdbcUrl())
.and("spring.datasource.username=" + mariaDB.getUsername())
.and("spring.datasource.password=" + mariaDB.getPassword())
.and("spring.kafka.bootstrap-servers=" + kafka.getBootstrapServers())
.applyTo(ctx);
}
}
private static void runMigrations() {
Flyway.configure()
.dataSource(mariaDB.getJdbcUrl(), mariaDB.getUsername(),
mariaDB.getPassword())
.locations(MIGRATION_LOCATION)
.schemas(mariaDB.getDatabaseName())
.baselineOnMigrate(true)
.load().migrate();
}
}
See Also
- 쿠…sal:
[컴] Spring Test 에서 @Sql 을 code 로