The Codest
  • 회사 소개
  • 서비스
    • 소프트웨어 개발
      • 프론트엔드 개발
      • 백엔드 개발
    • Staff Augmentation
      • 프론트엔드 개발자
      • 백엔드 개발자
      • 데이터 엔지니어
      • 클라우드 엔지니어
      • QA 엔지니어
      • 기타
    • IT 자문
      • 감사 및 컨설팅
  • 산업 분야
    • 핀테크 및 뱅킹
    • E-commerce
    • 애드테크
    • 헬스 테크
    • 제조
    • 물류
    • 자동차
    • IOT
  • 가치
    • CEO
    • CTO
    • 배달 관리자
  • 우리 팀
  • Case Studies
  • 방법 알아보기
    • 블로그
    • 모임
    • 웹 세미나
    • 리소스
채용 정보 연락하기
  • 회사 소개
  • 서비스
    • 소프트웨어 개발
      • 프론트엔드 개발
      • 백엔드 개발
    • Staff Augmentation
      • 프론트엔드 개발자
      • 백엔드 개발자
      • 데이터 엔지니어
      • 클라우드 엔지니어
      • QA 엔지니어
      • 기타
    • IT 자문
      • 감사 및 컨설팅
  • 가치
    • CEO
    • CTO
    • 배달 관리자
  • 우리 팀
  • Case Studies
  • 방법 알아보기
    • 블로그
    • 모임
    • 웹 세미나
    • 리소스
채용 정보 연락하기
뒤로 화살표 뒤로 가기
2022-07-26
소프트웨어 개발

테스트 컨테이너 - 테스트를 더 쉽게 만드는 방법은?

바르틀로미예 쿠친스키

더 쉽게 테스트할 수 있는 방법을 찾고 계신가요? 저희가 도와드리겠습니다! 다음 글을 확인하시고 어떻게 가능한지 알아보세요.

최신 애플리케이션 개발은 한 가지 간단한 규칙을 기반으로 합니다:

컴포지션 사용

우리는 클래스, 함수, 서비스를 더 큰 소프트웨어 조각으로 구성합니다. 이 마지막 요소는 마이크로서비스의 기초이며 육각형 아키텍처. 기존 솔루션을 사용하고 소프트웨어와 통합한 후 바로 시장.

계정 등록을 처리하고 사용자 데이터를 저장하고 싶으신가요? OAuth 서비스 중 하나를 선택할 수 있습니다. 애플리케이션에서 구독이나 결제를 제공하시나요? 이를 처리하는 데 도움이 되는 많은 서비스가 있습니다. 웹사이트에 대한 분석이 필요하지만 GDPR을 이해하지 못하시나요? 부담 없이 바로 사용할 수 있는 솔루션 중 하나를 선택하세요.

비즈니스 관점에서 보면 개발이 너무 쉬워도 간단한 테스트를 작성해야 하는 순간에는 두통이 생길 수 있습니다.

신비한 동물사전 대기열, 데이터베이스 및 테스트 방법

단위 테스트는 매우 간단합니다. 규칙만 준수하면 테스트 환경과 코드 건강합니다. 어떤 규칙이 있나요?

  • 쉬운 쓰기 - 단위 테스트는 많이 작성하기 때문에 작성하기 쉬워야 합니다. 수고가 적다는 것은 더 많은 테스트를 작성할 수 있다는 뜻입니다.
  • 읽기 가능 - 테스트 코드는 읽기 쉬워야 합니다. 테스트는 하나의 이야기입니다. 소프트웨어의 동작을 설명하며 문서화 지름길로 사용할 수 있습니다. 좋은 단위 테스트는 코드를 디버깅하지 않고도 버그를 수정하는 데 도움이 됩니다.
  • 신뢰성 - 테스트 중인 시스템에 버그가 있는 경우에만 테스트가 실패해야 합니다. 당연하죠? 항상 그런 것은 아닙니다. 테스트를 하나씩 실행하면 통과하지만 세트로 실행하면 실패하는 경우도 있습니다. 머신에서는 통과하지만 CI에서는 실패하는 경우(내 컴퓨터에서 작동). 좋은 단위 테스트의 실패 이유는 단 하나뿐입니다.
  • 빠른 - 테스트는 빨라야 합니다. 실행 준비, 시작 및 테스트 실행 자체도 매우 신속해야 합니다. 그렇지 않으면 테스트는 작성하지만 실행하지는 못합니다. 테스트가 느리면 집중력이 떨어집니다. 기다리면서 진행률 표시줄을 보게 됩니다.
  • 독립 - 마지막으로, 테스트는 독립적이어야 합니다. 이 규칙은 앞의 규칙에서 비롯된 것입니다. 진정으로 독립적인 테스트만 하나의 단위가 될 수 있습니다. 서로 간섭하지 않고, 어떤 순서로든 실행할 수 있으며, 잠재적인 실패가 다른 테스트의 결과에 의존하지 않습니다. 또한 독립적이라는 것은 데이터베이스, 메시징 서비스 또는 파일 시스템과 같은 외부 리소스에 대한 의존성이 없다는 의미이기도 합니다. 외부와 통신해야 하는 경우 모의, 스텁 또는 더미를 사용할 수 있습니다.

통합 테스트를 작성하려고 하면 모든 것이 복잡해집니다. 몇 가지 서비스를 함께 테스트하는 것은 나쁘지 않습니다. 하지만 데이터베이스나 메시징 서비스와 같은 외부 리소스를 사용하는 서비스를 테스트해야 할 때는 문제가 발생합니다.

테스트를 실행하려면 다음을 설치해야 합니다.

수년 전에는 데이터베이스 등을 통합 테스트하고 사용하고자 할 때 두 가지 옵션이 있었습니다:

  1. 로컬에 데이터베이스를 설치할 수 있습니다. 스키마를 설정하고 테스트에서 연결합니다;
  2. "공간 어딘가"에 있는 기존 인스턴스에 연결할 수 있습니다.

둘 다 장점도 있고 단점도 있습니다. 하지만 둘 다 추가적인 복잡성을 야기합니다. 때로는 특정 도구의 특성으로 인해 발생하는 기술적 복잡성(예: 로컬 호스트에 Oracle DB 설치 및 관리)이었습니다. 때로는 테스트에 동의해야 하는 등 프로세스의 불편함이 있었습니다. 팀 테스트를 실행할 때마다 JMS 사용에 대해 설명합니다.

구출할 컨테이너

지난 10년 동안 컨테이너화라는 개념은 업계에서 인정을 받았습니다. 따라서 통합 테스트 문제에 대한 해결책으로 컨테이너를 선택하는 것은 당연한 결정이었습니다. 컨테이너는 간단하고 깔끔한 솔루션입니다. 프로세스 빌드를 실행하기만 하면 모든 것이 작동합니다! 믿기지 않으시나요? 이 간단한 maven 빌드 구성을 살펴보세요:

<플러그인
   
     com.dkanejs.maven.plugins
     docker-compose-maven-plugin
     4.0.0
     
       
         up
         테스트-컴파일
         
           up</goal
         
         
           ${프로젝트.baseir}/docker-compose.yml
           true
         
       
       
         down
         통합 후 테스트
         
           다운</목표
         
         
           ${project.basedir}/docker-compose.yml
           true

그리고 docker-compose.yml 파일도 꽤 멋져 보입니다!

버전: "3.5"

서비스:

 postgres:
   컨테이너_이름: 리액티브B
   이미지: postgres:13.2
   restart: 항상
   환경
     - POSTGRES_USER=admin
     - POSTGRES_PASSWORD=password
     - POSTGRES_DB=cities
   포트
     - "5432:5432"
   volumes:
     - postgres_data:/데이터/db

 pgadmin:
   컨테이너_이름: pgadmin4
   이미지: dpage/pgadmin4
   restart: 항상
   환경
     PGADMIN_DEFAULT_EMAIL: [email protected]
     PGADMIN_DEFAULT_PASSWORD: 비밀번호
   포트
     - "15050:80"
   볼륨
     - pgadmin_data:/data/pgadmin

volumes:
 postgres_data:
 pgadmin_data:

하지만 여기서 문제를 발견할 수 있을까요?

모든 것을 차단하는 화물선

위의 예는 매우 간단합니다. 포스트그레스 데이터베이스인 pgAdmin 하나만 있으면 됩니다. 실행 시

bash
$ mvn 클린 확인

를 설정하면 maven 플러그인이 컨테이너를 시작하고 테스트가 끝나면 컨테이너를 끕니다. 프로젝트가 커지고 컴포즈 파일도 커지면 문제가 시작됩니다. 매번 모든 컨테이너를 시작해야 하며 전체 빌드 내내 컨테이너가 살아 있을 것입니다. 플러그인 실행 구성을 변경하여 상황을 조금 더 개선할 수 있지만 충분하지 않습니다. 최악의 시나리오에서는 테스트가 시작되기 전에 컨테이너가 시스템 리소스를 모두 소진합니다!

그리고 이것이 유일한 문제는 아닙니다. IDE에서 단일 통합 테스트를 실행할 수 없습니다. 그 전에는 컨테이너를 직접 시작해야 합니다. 또한, 다음번 maven을 실행하면 해당 컨테이너가 해체됩니다( down 실행).

따라서 이 솔루션은 대형 화물선과 같습니다. 모든 것이 잘 작동하면 괜찮습니다. 예기치 않거나 흔하지 않은 행동은 우리를 일종의 재앙으로 이끌 수 있습니다.

테스트 컨테이너 - 테스트에서 컨테이너 실행

하지만 테스트에서 컨테이너를 실행할 수 있다면 어떨까요? 이 아이디어는 좋아 보이며 이미 구현되고 있습니다. 테스트 컨테이너이 프로젝트에 대해 이야기하고 있기 때문에 여기에 우리의 문제에 대한 해결책이 있습니다. 이상적이지는 않지만 완벽한 사람은 없습니다.

이것은 Java 라이브러리를 사용하여 가볍고 쉽게 Docker 컨테이너를 실행할 수 있는 방법을 제공합니다. 이를 살펴보고 코드를 작성해 보겠습니다!

전제 조건 및 구성

시작하기 전에 구성을 확인해야 합니다. 테스트 컨테이너 필요:

  • 버전 17.09의 Docker,
  • Java 최소 버전 1.8,
  • 네트워크, 특히 docker.hub에 대한 액세스.

특정 OS 및 CI에 대한 요구 사항에 대한 자세한 내용은 다음에서 확인할 수 있습니다.
in 문서.

이제 다음에 몇 줄을 추가할 차례입니다. pom.xml.

저는 프로젝트에서 스프링 부트를 사용하여 상용구를 줄입니다. 테스트 컨테이너 는 스프링 프레임워크와 독립적이며 스프링 프레임워크 없이도 사용할 수 있습니다.
org.testcontainers
       testcontainers-bom
       ${testcontaines.version}
       pom
       import
     
   
 
 
   
     org.postgresql
     postgresql
     runtime
   
   
     org.testcontainers
     postgresql
     test
   
   
     org.testcontainers
     junit-jupiter
     test

사용 테스트 컨테이너 버전 1.17.3를 사용해야 하지만 최신 버전을 자유롭게 사용하세요.

Postgres 컨테이너를 사용한 테스트

첫 번째 단계는 컨테이너 인스턴스를 준비하는 것입니다. 테스트에서 직접 할 수도 있지만 독립 클래스가 더 좋아 보입니다.

public class Postgres13TC extends PostgreSQLContainer {

 비공개 정적 최종 Postgres13TC TC = new Postgres13TC();

 private Postgres13TC() {
   super("postgres:13.2");
 }

 public static Postgres13TC getInstance() {
   TC를 반환합니다;
 }

 @Override
 public void start() {
   super.start();
   System.setProperty("DB_URL", TC.getJdbcUrl());
   System.setProperty("DB_USERNAME", TC.getUsername());
   System.setProperty("DB_PASSWORD", TC.getPassword());
 }

 @Override
 public void stop() {
   // 아무것도 하지 않습니다. 이것은 공유 인스턴스입니다. 이 작업은 JVM이 처리하도록 합니다.
 }
}

테스트를 시작할 때 다음과 같은 인스턴스를 생성합니다. Postgres13TC. 이 클래스는 컨테이너에 대한 정보를 처리할 수 있습니다. 여기서 가장 중요한 것은 데이터베이스 연결 문자열과 자격 증명입니다. 이제 아주 간단한 테스트를 작성해 보겠습니다.

테스트 컨테이너
SimpleDbTest 클래스 {

 @Container
 비공개 정적 Postgres13TC = Postgres13TC.getInstance();

 @Test
 void testConnection() {
   assumeThat(postgres13TC.isRunning());
   var connectionProps = 새로운 속성();
   connectionProps.put("user", postgres13TC.getUsername());
   connectionProps.put("password", postgres13TC.getPassword());

   try (Connection = DriverManager.getConnection(postgres13TC.getJdbcUrl(),
       connectionProps)) {
     var resultSet = connection.prepareStatement("Select 1").executeQuery();
     resultSet.next();
     assertThat(resultSet.getInt(1)).isEqualTo(1);
   } catch (SQLException sqlException) {
     assertThat((Exception) sqlException).doesNotThrowAnyException();
   }
 }
}

여기서는 JUnit 5를 사용합니다. 주석 테스트 컨테이너 는 테스트 환경에서 컨테이너를 제어하는 확장 기능의 일부입니다. 이들은 모든 필드에 @Container 어노테이션과 시작 및 중지 컨테이너를 각각 설정합니다.

스프링 부트를 사용한 테스트

앞서 언급했듯이 저는 프로젝트에서 Spring Boot를 사용합니다. 이 경우 코드를 조금 더 작성해야 합니다. 첫 번째 단계는 추가 구성 클래스를 만드는 것입니다.

@Slf4j
공용 클래스 ContainerInit 구현
   ApplicationContextInitializer {

 public static Postgres13TC;

 static {
   postgres13TC = Postgres13TC.getInstance();
   postgres13TC.start();
 }

 @Override
 public void initialize(ConfigurableApplicationContext applicationContext) {
   TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
       applicationContext,
       "spring.datasource.url=" + postgres13TC.getJdbcUrl(),
       "spring.datasource.username=" + postgres13TC.getUsername(),
       "spring.datasource.password=" + postgres13TC.getPassword(),
       "db.host=" + postgres13TC.getHost(),
       "db.port=" + postgres13TC.getMappedPort(postgres13TC.POSTGRESQL_PORT),
       "db.name=" + postgres13TC.getDatabaseName(),
       "db.username=" + postgres13TC.getUsername(),
       "db.password=" + postgres13TC.getPassword()
   );
 }
}

이 클래스는 기존 프로퍼티를 다음과 같은 값으로 재정의합니다. 테스트 컨테이너. 처음 세 개의 프로퍼티는 표준 Spring 프로퍼티입니다. 다음 5개는 추가 사용자 정의 프로퍼티로, 예를 들어 liquibase와 같은 다른 리소스 및 확장을 구성하는 데 사용할 수 있습니다:

spring.liquibase.change-log=classpath:/db/changelog/dbchangelog.xml
spring.liquibase.url=jdbc:postgresql://${db.host:localhost}:${db.port:5432}/${db.name:cities}
spring.liquibase.user=${db.username:admin}
spring.liquibase.password=${db.password:password}
spring.liquibase.enabled=true

이제 간단한 통합 테스트를 정의할 차례입니다.

스프링부트테스트(웹환경 = RANDOM_PORT)
자동 구성 테스트 데이터베이스(대체 = NONE)
컨텍스트 구성(초기화자 = ContainerInit.class)
테스트 컨테이너
클래스 더미 리포지토리 테스트 {

 @Autowired
 비공개 DummyRepository;

 @Test
 void shouldReturnDummy() {
   var byId = dummyRepository.getById(10L);
   var expected = new Dummy();
   expected.setId(10L);
   assertThat(byId).completes().emitsCount(1).emits(expected);
 }
}

여기에 몇 가지 추가 주석이 있습니다.

  • 스프링부트테스트(웹환경 = RANDOM_PORT) - 는 테스트를 Spring Boot 테스트로 표시하고 스프링 컨텍스트를 시작합니다.
  • 자동 구성 테스트 데이터베이스(대체 = NONE) - 이 주석은 스프링 테스트 확장이 메모리 구성에서 포스트그레스 데이터베이스 구성을 H2로 대체해서는 안 된다고 말합니다.
  • 컨텍스트 구성(초기화자 = ContainerInit.class) - 추가 스프링 컨텍스트
    구성에서 속성을 설정하는 테스트 컨테이너.
  • 테스트 컨테이너 - 앞서 언급했듯이 이 어노테이션은 컨테이너 수명 주기를 제어합니다.

이 예에서는 리액티브 리포지토리를 사용하지만 일반적인 JDBC 및 JPA 리포지토리에서도 동일하게 작동합니다.

이제 이 테스트를 실행할 수 있습니다. 처음 실행하는 경우 엔진이 docker.hub에서 이미지를 가져와야 합니다. 잠시 시간이 걸릴 수 있습니다. 그 후 두 개의 컨테이너가 실행된 것을 볼 수 있습니다. 하나는 포스트그레스이고 다른 하나는 테스트컨테이너 컨트롤러입니다. 두 번째 컨테이너는 실행 중인 컨테이너를 관리하며, JVM이 예기치 않게 중지되더라도 컨테이너를 끄고 환경을 정리합니다.

요약해 보겠습니다.

테스트 컨테이너 는 Docker 컨테이너를 사용하는 통합 테스트를 만드는 데 도움이 되는 매우 사용하기 쉬운 도구입니다. 이를 통해 유연성이 향상되고 개발 속도가 빨라집니다. 테스트 구성을 올바르게 설정하면 새로운 개발자를 합류시키는 데 필요한 시간이 단축됩니다. 모든 종속성을 설정할 필요 없이 선택한 구성 파일로 작성된 테스트를 실행하기만 하면 됩니다.

협력 배너

관련 문서

소프트웨어 개발

미래 지향적인 웹 앱 구축: The Codest의 전문가 팀이 제공하는 인사이트

The Codest가 최첨단 기술로 확장 가능한 대화형 웹 애플리케이션을 제작하고 모든 플랫폼에서 원활한 사용자 경험을 제공하는 데 탁월한 성능을 발휘하는 방법을 알아보세요. Adobe의 전문성이 어떻게 디지털 혁신과 비즈니스를 촉진하는지 알아보세요...

최신
소프트웨어 개발

라트비아에 본사를 둔 10대 소프트웨어 개발 기업

최신 기사에서 라트비아 최고의 소프트웨어 개발 기업과 그들의 혁신적인 솔루션에 대해 알아보세요. 이러한 기술 리더들이 어떻게 귀사의 비즈니스를 향상시키는 데 도움을 줄 수 있는지 알아보세요.

thecodest
엔터프라이즈 및 스케일업 솔루션

Java 소프트웨어 개발 필수 사항: 성공적인 아웃소싱을 위한 가이드

The Codest로 효율성을 높이고 전문 지식을 활용하며 프로젝트 성공을 이끌 수 있는 성공적인 outsourcing Java 소프트웨어 개발에 대한 이 필수 가이드를 살펴보세요.

thecodest
소프트웨어 개발

폴란드 아웃소싱을 위한 최고의 가이드

폴란드에서 outsourcing가 급증한 것은 경제, 교육, 기술 발전으로 인한 IT 성장과 비즈니스 친화적인 환경이 조성된 덕분입니다.

더코데스트
엔터프라이즈 및 스케일업 솔루션

IT 감사 도구 및 기술에 대한 완벽한 가이드

IT 감사는 안전하고 효율적이며 규정을 준수하는 시스템을 보장합니다. 전체 기사를 읽고 그 중요성에 대해 자세히 알아보세요.

The Codest
야쿱 야쿠보비치 CTO & 공동 설립자

지식창고를 구독하고 IT 분야의 전문 지식을 최신 상태로 유지하세요.

    회사 소개

    The Codest - 폴란드에 기술 허브를 둔 국제 소프트웨어 개발 회사입니다.

    영국 - 본사

    • 사무실 303B, 182-184 하이 스트리트 노스 E6 2JA
      영국 런던

    폴란드 - 현지 기술 허브

    • 파브리츠나 오피스 파크, 알레야
      포코주 18, 31-564 크라쿠프
    • 뇌 대사관, 콘스트럭터스카
      11, 02-673 바르샤바, 폴란드

      The Codest

    • 홈
    • 회사 소개
    • 서비스
    • Case Studies
    • 방법 알아보기
    • 채용 정보
    • 사전

      서비스

    • IT 자문
    • 소프트웨어 개발
    • 백엔드 개발
    • 프론트엔드 개발
    • Staff Augmentation
    • 백엔드 개발자
    • 클라우드 엔지니어
    • 데이터 엔지니어
    • 기타
    • QA 엔지니어

      리소스

    • 외부 소프트웨어 개발 파트너와의 협력에 대한 사실과 오해
    • 미국에서 유럽으로: 미국 스타트업이 유럽으로 이전을 결정하는 이유
    • 테크 오프쇼어 개발 허브 비교: 테크 오프쇼어 유럽(폴란드), 아세안(필리핀), 유라시아(터키)
    • CTO와 CIO의 주요 과제는 무엇인가요?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • 웹사이트 이용 약관

    저작권 © 2025 by The Codest. 모든 권리 보유.

    ko_KRKorean
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian jaJapanese es_ESSpanish nl_NLDutch etEstonian elGreek ko_KRKorean