File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
package kr.itn.itnhub;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.PostgreSQLContainer;
/**
* Spring 컨텍스트를 실제로 로딩해야 하는 테스트의 공통 베이스.
*
* <p>Testcontainers PostgreSQL 컨테이너를 띄우고, 애플리케이션 구동에 필요한
* {@code mattermost.*} / {@code app.admin.*} 필수 프로퍼티를 더미 값으로 채워
* 컨텍스트 리프레시가 실제 외부 시스템 없이도 성공하도록 한다.</p>
*
* <p><b>싱글턴 컨테이너 패턴.</b> 컨테이너는 테스트 JVM 전체에서 단 한 번만
* static 초기화 블록에서 직접 {@code start()} 하고, JUnit5의 {@code @Testcontainers}/
* {@code @Container} 확장은 의도적으로 쓰지 않는다. 그 확장을 쓰면 매 테스트 클래스가
* 끝날 때마다 컨테이너가 stop 되는데, Spring의 테스트 컨텍스트 캐시는 동일한 설정을
* 공유하는 다음 {@code AbstractDbTest} 하위 클래스에 대해 이미 만들어진
* {@code ApplicationContext}(및 그 안에서 죽은 포트를 가리키는 {@code DataSource})를
* 그대로 재사용해버려, 두 번째로 실행되는 DB 테스트 클래스가 "Connection refused"로
* 깨진다(전체 스위트에서만 재현되고 단독 실행 시엔 통과하는 이유). 여기서 컨테이너를
* 한 번만 띄우고 절대 {@code stop()} 하지 않으면(JVM 종료 시 Ryuk 사이드카가 정리)
* 모든 하위 테스트 클래스가 동일한 살아있는 컨테이너를 공유하므로 이 문제가 사라진다.</p>
*/
@SpringBootTest
public abstract class AbstractDbTest {
@ServiceConnection
static final PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16");
static {
postgres.start();
}
@DynamicPropertySource
static void secrets(DynamicPropertyRegistry registry) {
registry.add("app.admin.username", () -> "admin");
registry.add("app.admin.password", () -> "test-password");
registry.add("mattermost.base-url", () -> "http://localhost:1");
registry.add("mattermost.token", () -> "test-token");
registry.add("mattermost.team-id", () -> "test-team");
}
}