통합 테스트를 덜 불안정하게 만드는 방법

단위 테스트는 훌륭합니다. 그들은 빨리 달립니다. 작업을 검증하는 데 도움이 될 수 있습니다. 향후 변경을 더 쉽게 만듭니다. 그들은 복잡한 논리 비트에 대한 사양 역할을 할 수 있습니다.

그러나 일반적으로 인터페이스에서 문제가 발생합니다. 내 코드가 데이터베이스, 파일 시스템 또는 다른 서비스와 통신할 때 문제가 발생합니다. 이러한 이유로 통합 테스트가 유용합니다. 파일 시스템, 데이터베이스 또는 원격 시스템에서 쓰기 및 읽기를 테스트할 수 있습니다. 코드 적용 범위 측면에서 통합 테스트는 이길 수 없습니다.



하지만 문제가 있습니다. 그것들을 실행하는 것이 더 어렵습니다. 특히 팀에 속해 있고 병렬 개발의 각 분기에 대해 실행하려는 경우.



다음은 간단한 예입니다. 알파벳순으로 상위 5개 국가를 인쇄하는 애플리케이션이 있습니다. 국가는 Postgres에서 왔습니다. 예는 Scala에 있지만 내 요점은 희망적으로 더 보편적입니다.

> sbt run
The first 5 countries are Afghanistan, Albania, Algeria, American Samoa, Andorra


또한 데이터베이스에 5개 국가를 성공적으로 들어오고 나갈 수 있는 간단한 통합 테스트도 있습니다. 이 예제의 전체 코드is here .

class DatabaseIntegrationTest extends FlatSpec {
  implicit val cs = IO.contextShift(ExecutionContext.global)

...

  "A table" should "have country data" in {
    val dal = new DataAccessLayer()
    assert(dal.countries(5).transact(xa).unsafeRunSync.size == 5)
  }
}


산출:

>sbt it:test
[info] DatabaseIntegrationTest:
[info] A table
[info] - should have country data
[info] Run completed in 2 seconds, 954 milliseconds.
[info] Total number of tests run: 1


로컬에서 이것을 개발하는 동안 docker-compose 파일을 사용하여 데이터베이스 및 기타 종속성을 시작합니다.

version: "3"
services:
  postgres:
    container_name: local-postgres
    image: aa8y/postgres-dataset:iso3166
    ports:
      - 5432:5432
    hostname: postgres
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
  postgres-ui:
    container_name: local-postgres-ui
    image: adminer:latest
    depends_on:
      - postgres
    ports:
      - 8080:8080
    hostname: postgres-ui


하지만 이 테스트와 다른 테스트를 빌드 파이프라인의 일부로 실행하고 싶습니다. 변경 사항이 이 테스트를 중단하는 경우 나중에 GitHub Actions 또는 Jenkins에서 알려 주기를 원합니다. 그러나 어떤 데이터베이스를 가리키고 있습니까?

테스트 환경 솔루션



이에 대한 한 가지 해결책은 테스트 환경을 사용하는 것입니다. 실제 생산 세계가 어떤 모습이든 간에 테스트를 위해 사본을 만들고 이에 대해 테스트를 실행하십시오.


이 솔루션은 더 많은 문제를 가져옵니다. 한 가지 문제는 재현성입니다. 단 한 사람이 단일 서비스에서 하나의 종속성으로 작업하는 경우 테스트 환경이 적합할 것입니다. 그러나 더 많은 사람들이 병렬 브랜치에서 작업하기 시작하고 더 많은 서비스가 등장하면 상황이 무너지기 시작할 것입니다.

다음은 실제 경험을 기반으로 한 몇 가지 문제입니다.
  • 수정된 데이터: 병렬 테스트가 내가 의존하는 일부 상태를 수정했기 때문에 테스트 실행이 실패했습니다.
  • 데이터 누락: 데이터베이스의 샘플 데이터가 제거되었기 때문에 테스트 실행이 실패했습니다.
  • 새 데이터: 다른 분기의 다른 통합 테스트가 해당 데이터를 제대로 정리하지 않았기 때문에 실패합니다.



  • 문제의 핵심은 병렬로 테스트하고 싶지만 테스트 환경이 하나뿐이라는 것입니다. 서비스 수가 증가함에 따라 문제는 더욱 악화될 것입니다.

    솔루션



    이러한 각 문제에 대한 특정 솔루션이 있습니다. 그러나 귀하의 서비스가 더 많은 다른 서비스에 의존함에 따라 깨끗한 상태를 유지하기가 점점 더 어려워집니다. 잠재적인 해결책이 있습니다.



    여기서 문제의 핵심은 통합 테스트 실행 사이에 진정한 격리가 없다는 것입니다.

    솔루션은 통합 테스트를 실행하기 위해 로컬 및 빌드에서 종속성의 docker-compose 파일을 사용하는 것입니다.

    이것은 make 파일이나 bash 스크립팅을 사용하여 수행할 수 있지만 earthly로 수행할 수 있는 방법을 보여 드리겠습니다.

    저는 일종의 docker 파일과 make 파일의 조합과 같은 Earthfile을 만듭니다. 여기에서 소스를 복사하고 docker-compose up을 시작하고 테스트를 실행하는 통합 대상을 만듭니다.

    integration-test:
        FROM +project-files
        COPY src src
        COPY docker-compose.yml ./ 
        WITH DOCKER --compose docker-compose.yml
           RUN sbt it:test
        END
    


    그런 다음 로컬 또는 빌드 파이프라인에서 실행할 수 있으며 모든 실행은 서로 격리됩니다. 어디에서 실행되든 컨테이너화를 통해 모든 테스트 실행이 격리됩니다.

    > earth -P +integration-test
    +integration-test | Creating local-postgres ... done
    +integration-test | Creating local-postgres-ui ... done
    +integration-test | +integration-test | [info] Loading settings for project scala-example-build from plugins.sbt ...
    +integration-test | [info] DatabaseIntegrationTest:
    +integration-test | [info] An table
    +integration-test | [info] - should have country data
    +integration-test | [info] Run completed in 2 seconds, 923 milliseconds.
    +integration-test | [info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
    +integration-test | Stopping local-postgres-ui ... done
    +integration-test | Stopping local-postgres    ... done
    +integration-test | Removing local-postgres-ui ... done
    +integration-test | Removing local-postgres    ... done
    +integration-test | Removing network scala-example_default
    +integration-test | Target github.com/earthly/earthly-example-scala/integration:master+integration-test built successfully
    ...
    


    이 패턴을 사용하면 서비스가 docker-compose에서 종속성을 선언하고 통합 테스트가 덜 불안정해집니다.

    더 완전한 기능을 갖춘 버전example here과 더 긴 가이드 버전here이 있습니다.

    단위 테스트와 통합 테스트의 차이점에 대해 알아보고 싶다면 이에 대해서도 설명했습니다here .

    이것이 제가 이 문제를 해결하는 방법입니다. 어떤 솔루션을 보았습니까?

    좋은 웹페이지 즐겨찾기