확장 가능하고 부작용이없는 통합 테스트를 작성하는 방법은 무엇입니까?


14

현재 프로젝트에서 부작용이없는 확장 가능한 통합 테스트를 생성하기위한 좋은 솔루션을 찾기가 어려워지고 있습니다. 부작용이없는 속성에 대한 약간의 설명 : 주로 데이터베이스에 관한 것입니다. 테스트가 완료된 후 데이터베이스에 변경 사항이 없어야합니다 (상태는 유지되어야 함). 확장 성과 상태 보존이 함께 제공되지는 않지만 더 나은 솔루션을 원합니다.

다음은 일반적인 통합 테스트입니다 (이 테스트는 데이터베이스 계층에 닿음).

public class OrderTests {

    List<Order> ordersToDelete = new ArrayList<Order>(); 

    public testOrderCreation() {
        Order order = new Order();
        assertTrue(order.save());
        orderToDelete.add(order);
    }

    public testOrderComparison() {
        Order order = new Order();
        Order order2 = new Order();
        assertFalse(order.isEqual(order2);
        orderToDelete.add(order);
        orderToDelete.add(order2);
    }
    // More tests

    public teardown() {
         for(Order order : ordersToDelete)
             order.delete();
    }
}

상상할 수 있듯이이 방법은 테스트 속도가 매우 느립니다. 또한 전체 통합 테스트에 적용될 때 시스템의 작은 부분 만 테스트하는 데 약 5 초가 걸립니다. 적용 범위가 증가하면이 숫자가 증가한다고 상상할 수 있습니다.

그러한 테스트를 작성하는 또 다른 방법은 무엇입니까? 내가 생각할 수있는 한 가지 대안은 클래스 내에서 일종의 전역 변수를 갖는 것이며 모든 테스트 방법은이 변수를 공유합니다. 결과적으로 주문이 생성 및 삭제되는 경우는 거의 없습니다. 더 빠른 테스트 결과. 그러나 이것이 더 큰 문제를 초래한다고 생각합니다. 테스트는 더 이상 격리되지 않으며 테스트를 이해하고 분석하기가 점점 더 어려워집니다.

통합 테스트가 단위 테스트만큼 자주 실행되는 것은 아닙니다. 따라서 성능이 낮을 수 있습니다. 어쨌든 누군가가 확장 성을 향상시키기위한 대안을 생각해내는 것이 좋을 것입니다.

답변:


6

단위 테스트를 위해 Hypersonic 또는 다른 메모리 내 DB를 사용하십시오. 테스트가 더 빨리 실행될뿐만 아니라 부작용도 관련이 없습니다. (각 테스트 후 트랜잭션을 롤백하면 동일한 인스턴스에서 많은 테스트를 실행할 수도 있습니다)

또한 프로덕션 데이터베이스에서 발생하는 문제로 인해 테스트 실패를 시작할 수 없으며 "클린 데이터베이스 설치"에 대한 시작점을 제공하므로 데이터 모형을 만들어야합니다. "는 기존 프로덕션 사이트에 연결하지 않고 애플리케이션의 새 인스턴스를 갑자기 배포해야하는 경우에 도움이됩니다.

예,이 방법을 직접 사용합니다. 예, 처음 시간을 설정하는 것은 PITA 였지만 완료하려는 프로젝트 기간 동안 자체적으로 지불하는 것 이상입니다. 데이터 모형에 도움이되는 여러 도구도 있습니다.


좋은 생각 인 것 같습니다. 나는 특히 그것의 완전한 격리 측면을 좋아한다; 새로운 데이터베이스 설치로 시작합니다. 약간의 노력이 필요한 것 같지만 일단 설정하면 매우 유용합니다. 감사.
Guven

3

이것은 통합 테스트를 작성하는 동안 모든 사람이 직면하는 영원한 문제입니다.

이상적인 솔루션, 특히 프로덕션에서 테스트하는 경우 설정에서 트랜잭션을 열고 해체하여 롤백하는 것입니다. 나는 이것이 당신의 필요에 맞아야한다고 생각합니다.

가능하지 않은 경우 (예 : 클라이언트 계층에서 앱을 테스트하는 경우) 다른 솔루션은 가상 머신에서 DB를 사용하고 설정에서 스냅 샷을 작성하고 분해하여 다시 돌아가는 것입니다. 당신이 기대할 수있는 한 오래 걸릴).


트랜잭션 롤백을 생각하지 않았다는 것을 믿을 수 없습니다. 이 아이디어를 솔루션에 대한 빠른 수정으로 사용하지만 궁극적으로 인 메모리 DB는 매우 유망합니다.
Guven

3

통합 테스트는 항상 프로덕션 설정에 대해 실행해야합니다. 귀하의 경우 동일한 데이터베이스 및 응용 프로그램 서버가 있어야 함을 의미합니다. 물론 성능을 위해 메모리 내 DB를 사용하기로 결정할 수 있습니다.

하지만 절대로하지 말아야 할 것은 거래 범위를 확장하는 것입니다. 어떤 사람들은 트랜잭션을 통제하고 테스트 후에 롤백하도록 제안했습니다. 이렇게하면 모든 엔터티 (JPA를 사용한다고 가정) 테스트 실행 전체에서 지속성 컨텍스트연결되어 있습니다. 이로 인해 찾기매우 어려운 일부 불쾌한 버그가 발생할 수 있습니다 .

대신 JPAUnit 과 같은 라이브러리 또는 이 방법 과 유사한 라이브러리를 통해 모든 테스트 후에 데이터베이스를 수동으로 지워야합니다 (JDBC를 사용하여 모든 테이블 지우기).

성능 문제로 모든 빌드에서 통합 테스트를 실행해서는 안됩니다. 지속적인 통합 서버가이를 수행하도록하십시오. Maven을 사용하는 경우 테스트를 단위 테스트와 통합 테스트로 분리 할 수있는 안전 장치 플러그인을 사용할 수 있습니다.

또한, 당신은 아무것도 조롱해서는 안됩니다. 런타임 테스트 환경 내에서의 동작 테스트와 같은 통합 테스트를 기억하십시오.


좋은 대답입니다. 한 가지 요점 : 일부 외부 종속성 (예 : 이메일 전송)을 조롱하는 것이 허용 될 수 있습니다. 그러나 Java 코드로 모방하지 않고 완전한 모의 서비스 / 서버를 설정하여 모의해야합니다.
sleske

슬 스케, 동의합니다. 특히 JPA, EJB, JMS를 사용하거나 다른 스펙에 대해 구현하는 경우. 애플리케이션 서버, 지속성 제공자 또는 데이터베이스를 교체 할 수 있습니다. 예를 들어 임베디드 Glassfish 및 HSQLDB를 사용하여 간단히 설정하고 속도를 향상시킬 수 있습니다 (물론 인증 된 다른 구현을 자유롭게 선택할 수 있음).
BenR

2

확장 성

통합 테스트를 실행하는 데 시간이 너무 오래 걸리고 단일 개발자가 빡빡한 피드백 루프에서 지속적으로 실행하기에는 실용적이지 않다는 점에서이 문제가 발생하기도했습니다. 이에 대처하기위한 몇 가지 전략은 다음과 같습니다.

  • 적은 통합 테스트 작성 -시스템의 단위 테스트를 잘 다루는 경우 통합 테스트는 서로 다른 구성 요소가 함께 작동하는 방식에 대한 (ahem) 통합 문제에보다 중점을 두어야합니다. 연기 테스트와 비슷하지만 시스템이 여전히 전체적으로 작동하는지 확인하려고합니다. 따라서 이상적으로 단위 테스트는 응용 프로그램의 대부분의 기능적 부분을 포괄하며 통합 테스트는 해당 부분이 서로 어떻게 상호 작용하는지 확인합니다. 여기서는 논리 경로에 대한 광범위한 적용 범위가 필요하지 않으며 시스템을 통과하는 중요한 경로 만 있습니다.
  • 한 번에 테스트의 하위 집합 만 실행하십시오 . 일부 기능을 작업하는 단일 개발자는 일반적으로 해당 기능을 다루기 위해 어떤 테스트가 필요한지 잘 알고 있습니다. 변경 사항을 다루는 데 적합한 테스트 만 실행하십시오. JUnit과 같은 프레임 워크를 사용하면 카테고리에서 조명기그룹화 할 수 있습니다 . 보유하고있는 각 기능에 대한 최상의 적용 범위를 허용하는 그룹화를 작성하십시오. 물론, 소스 제어 시스템에 커밋하기 전과 지속적 통합 서버에서 어느 시점 에나 모든 통합 테스트를 계속 실행하려고합니다.
  • 시스템 최적화 -일부 성능 테스트와 결합 된 통합 테스트 는 시스템의 느린 부분을 조정하는 데 필요한 입력을 제공하여 테스트가 나중에 더 빨리 실행될 수 있습니다. 이를 통해 데이터베이스에서 필요한 인덱스, 서브 시스템 간의 복잡한 인터페이스 또는 주소 지정이 필요한 기타 성능 병목 현상을 발견 할 수 있습니다.
  • 병렬 테스트를 실행 - 당신이 직교 테스트의 그룹화 좋은이있는 경우에 그 실행을 시도 할 수 평행 . 내가 언급 한 직교 요구 사항에 주의를 기울여야 합니다. 테스트가 서로 발에 밟 히기를 원하지 않습니다.

효과를 높이려면 이러한 기술을 결합하십시오.


1
정말 좋은 지침; 적은 수의 통합 테스트를 작성하는 것이 최선의 조언입니다. 또한, 그것들을 병렬로 실행하는 것이 매우 좋은 대안이 될 것입니다. 격리 측면에서 직접 테스트를 받았는지 확인하기위한 완벽한 "테스트".
Guven

2

테스트 목적으로 우리는 파일 기반의 SQLite 데이터베이스 배포를 사용했습니다 (자원을 복사하기 만하면 됨). 이를 통해 스키마 마이그레이션을 테스트 할 수도 있습니다. 내가 아는 한, 스키마 변경은 트랜잭션이 아니므로 트랜잭션이 중단 된 후에 롤백되지 않습니다. 또한 테스트 설정을 위해 트랜잭션 지원에 의존 할 필요가 없으므로 응용 프로그램의 트랜잭션 동작을 올바르게 테스트 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.