•
10장에서 다루는 내용
◦
데이터베이스 테스트를 위한 전제 조건
◦
데이터베이스 테스트 모범 사례
◦
테스트 데이터 생명 주기
◦
테스트 내 데이터베이스 트랜잭션 관리
•
통합 테스트라는 퍼즐의 마지막 조각은 프로세스 외부 의존성 중, 관리 의존성이다.
◦
가장 일반적인 예로 어플리케이션 데이터베이스가 존재한다. 이는 다른 어플리케이션에서 접근이 불가능한 데이터베이스다.
•
이 장에서는 데이터베이스 테스트를 시작하기 전에 거쳐야 할 준비 단계를 살펴본다.
◦
데이터베이스 스키마를 추적하고 상태 기반 데이터베이스 배포 방식과 마이그레이션 기반 데이터베이스 배포 방식의 차이점을 설명하며 마이그레이션 기반을 선택해야 하는 이유를 알아본다.
•
기본 지식을 학습한 후 테스트 중, 트랜잭션을 관리하는 방법과 남은 데이터를 처리하는 방법 그리고 중요하지 않은 부분은 제거하고 필수 요소를 강조하해 테스트를 작게할 수 있는 방법을 살펴본다.
1. 데이터베이스 테스트를 위한 전제 조건
•
통합 테스트에서 관리 의존성은 대체되지 않아야 한다. 목을 사용하는 것이 불가능하므로 비관리 의존성보다 작업이 더 어려울 수 있다.
•
그러나 테스트를 작성하기 전 통합 테스트가 가능하게끔 데이터베이스를 준비하는 단계를 거쳐야 한다. 이 절에서는 다음과 같은 전제 조건을 살펴본다.
◦
형상 관리 시스템에 데이터베이스 유지
◦
모든 개발자를 위한 별도의 데이터베이스 인스턴스 사용
◦
데이터베이스 배포에 마이그레이션 기반 방식 적용
1.
데이터베이스를 형상 관리 시스템에 유지
•
데이터베이스를 테스트하는 첫 단계는 데이터베이스 스키마를 일반 코드로 취급하는 것이다. 일반 코드와 마찬가지로 데이터베이스 스키마를 Git과 같은 형상 관리 시스템에 저장하는 것이 최선이다.
•
개발을 진행함에 있어서 모델 데이터베이스를 두고 개발을 진행했다. 개발은 모델 데이터베이스를 토대로 진행했고 운영은 운영 데이터베이스를 사용했다.
◦
운영 배포할 때, 팀은 운영 데이터베이스와 모델 데이터베이스를 비교하고 업그레이드 스크립트를 생성하기 위한 전문 도구를 사용했으며 운영 환경에서 스크립트를 실행해 반영하였다.
•
모델 데이터베이스를 두는 것은 데이터베이스 스키마를 유지하는 데 상당히 좋지 못한 방법이다. 그 이유는 다음과 같다.
◦
변경 내역 부재
▪
버전 정보가 존재하지 않으므로 데이터베이스 스키마를 과거의 특정 시점으로 롤백할 수 없다. 이는 운영 환경에서 버그를 재현할 때 중요할 수 있다.
◦
복수의 원천 정보
▪
모델 데이터베이스는 개발 상태에 대한 원천 정보를 둘러싸고 경합하게 된다. 이렇게 기준을 둘로 두게되면 부담이 가중된다.
•
모든 데이터베이스 스키마 업데이트를 형상 관리 시스템에 두면 원천 정보를 하나로 할 수 있고 일반 코드 변경과 함께 데이터베이스 변경을 추적할 수 있다. 형상 관리 외부에선 데이터베이스 구조 수정이 발생하지 않아야 한다.
2.
참조 데이터도 데이터베이스 스키마다
•
데이터베이스 스키마의 정보들에는 테이블, 뷰, 인덱스, 저장 프로시저 및 데이터베이스의 구조를 형성하는 기타 다른 요소들이 있다.
•
스키마는 SQL 스크립트 형태로 표현되는데, 개발 중에 언제든지 스크립트로 기능을 가지고 있는 데이터베이스 인스턴스를 생성해낼 수 있어야 한다.
•
데이터베이스 스키마에 속하지만 우리가 데이터베이스 스키마로 여기지 않는 부분이 있다. 바로 참조 데이터다.
◦
참조 데이터는 어플리케이션이 동작하는 데 필요한 데이터들이다.
◦
UserType, Status와 같은 비즈니스 로직을 일부 담당하고 있는 데이터들이다.
•
참조 데이터는 어플리케이션의 필수 사항이므로 테이블, 뷰 그리고 다른 데이터베이스 스키마와 함께 SQL Insert 문 형태로 형상 관리 시스템에 저장해야 한다.
3.
모든 개발자를 위한 별도의 데이터베이스 인스턴스
•
실제 데이터베이스로 테스트하는 것은 충분히 어렵다. 다른 개발자들과 데이터베이스를 공유한다면 훨씬 더 어려워진다. 이유는 다음과 같다.
◦
서로 다른 개발자가 데이터베이스를 이용해 실행한 테스트는 간섭을 일으킬 수 있다.
◦
하위 호환성이 없는 변경으로 다른 개발자의 작업을 막을 수 있다.
•
테스트 피드백 속도를 극대화하려면 개발자마자 별도의 데이터베이스 인스턴스를 사용하는 것이 좋다.
4.
상태 기반 데이터베이스 배포와 마이그레이션 기반 데이터베이스 배포
•
마이그레이션 기반 방식은 초기 비용이 많이 발생하나 장기적으로 상태 기반 데이터베이스보다 훨씬 효과적이다.
•
상태 기반 방식
◦
앞서 설명한 방식이 상태 기반 방식이다. 개발 내내 유지보수하는 모델 데이터베이스가 존재하고 배포 시에는 비교 도구를 이용해 스크립트를 생성하여 운영 데이터베이스를 최신화한다.
◦
차이점은 상태 기반 방식을 사용하면 물리적인 모델 데이터베이스는 운영 데이터베이스와는 다르다는 것이다. 대신 해당 데이터베이스를 작성하는데 사용할 수 있는 SQL 스크립트가 있다.
◦
스크립트는 형상 관리 시스템에 저장되는데, 비교 도구는 불필요한 테이블을 삭제하고 새 테이블을 생성하고 컬럼명을 바꾸는 등 모델 데이터베이스와 동기화하는데 필요한 모든 작업을 수행한다.
•
마이그레이션 방식
◦
마이그레이션 기반 방식은 데이터베이스를 어떤 버전에서 다른 버전으로 전환하는 명시적인 마이그레이션을 의미한다.
◦
이 방식은 운영 데이터베이스와 개발 데이터베이스를 자동으로 동기화하기 위한 도구를 사용할 수 없고 업그레이드 스크립트를 직접 작성해야 한다.
◦
하지만 운영 데이터베이스 스키마에서 문서화되지 않은 변경사항을 발견할 때 데이터베이스 비교 도구가 아직 유용할 수 있다.
◦
마이그레이션 방식에서 형상 관리 시스템에 저장되는 산출물은 데이터베이스 상태가 아닌 마이그레이션이다. 이는 일반적으로 SQL 스크립트로 표시하지만 DSL을 사용해서 작성할 수도 있따.
•
상태 기반 방식보다 마이그레이션 기반 방식을 선호하라
◦
데이터베이스 배포와 관련해 차이점은 상태와 마이그레이션에서 온다.
▪
상태 기반 방식은 상태를 형상 관리에 저장하여 상태를 명시하고 비교 도구가 마이그레이션을 암묵적으로 제어하도록 한다.
▪
마이그레이션 기반 방식은 마이그레이션을 명시적으로 수행하지만 상태를 암묵적으로 둔다. 데이터베이스 상태를 저장하지 않으며 마이그레이션으로 조합해야 한다.
데이터베이스 상태 | 마이그레이션 메커니즘 | |
상태 기반 | 명시적 | 암묵적 |
마이그레이션 기반 | 암묵적 | 명시적 |
◦
데이터베이스 상태가 명확하면 병합 충돌을 처리하는 것이 수월하나 명시적인 마이그레이션은 데이터 모션 문제를 해결하는데 도움이 된다.
▪
데이터 모션은 새로운 데이터베이스를 준수하도록 기존 데이터의 형태를 변경하는 과정이다. 일반적으로 대부분의 프로젝트에서는 데이터 모션이 병합 충돌보다 훨씬 더 중요하다.
2. 데이터베이스 트랜잭션 관리
•
데이터베이스 트랜잭션 관리는 제품 코드와 테스트 코드 모두 중요한 주제다.
◦
제품 코드에서 트랜잭션 관리를 적절히 수행하면 데이터 모순을 피할 수 있다.
◦
테스트 코드에서는 운영 환경에 근접한 설정으로 데이터베이스 연결을 검증하는 데 도움이 된다.
•
이 절에서는 먼저 제품 코드에서 트랜잭션을 처리하는 방법과 통합 테스트에서 트랜잭션을 사용하는 방법을 알아본다.
1.
제품 코드에서 데이터베이스 트랜잭션 관리하기
•
조회 연산의 경우, 여러 트랜잭션을 열어도 괜찮다. 그러나 조작 연산이 발생하는 경우, 데이터 모순을 피하고자 조작 연산이 포함된 모든 업데이트는 원자적이어야 한다.
•
데이터베이스 트랜잭션에서 데이터베이스 연결 분리하기
◦
잠재적인 모순을 피하려면 결정 유형을 둘로 나누어야 한다.
▪
업데이트할 데이터
▪
업데이트 유지 또는 롤백 여부
◦
컨트롤러가 모든 비즈니스 로직의 모든 단계가 성공했을 때 업데이트를 수행할 수 있는지 여부만 안다. 또한 데이터베이스에 접근하고 업데이트를 시도해야만 이러한 단계를 밟을 수 있다.
◦
Database 클래스를 레포지터리와 트랜잭션으로 나눠서 이러한 책임을 구분할 수 있다.
▪
레포지터리는 데이터베이스의 데이터에 대한 접근과 수정을 가능하게 하는 클래스다.
▪
트랜잭션은 데이터 업데이트를 완전히 커밋하거나 롤백하는 클래스다. 데이터 수정의 원자성 확보를 위해 기본 데이터베이스 트랜잭션에 의존하는 사용자 정의 클래스다.
◦
레포지터리와 트랜잭션은 책임이 서로 다를 뿐만 아니라 수명도 다르다.
▪
트랜잭션은 비즈니스 연산 동안 있으며 연산이 끝나면 사라진다.
▪
레포지터리는 수명이 짧다 데이터베이스 호출이 완료되는 즉시 레포지터리의 쓰임이 종료되므로 폐기할 수 있다.
◦
결국 레포지터리는 트랜잭션 밑에서 동작한다. 데이터베이스에 연결할 때는 레포지터리가 트랜잭션에 등록해서 이뤄진 모든 데이터 수정이 나중에 트랜잭션에 의해 롤백될 수 있도록 한다.
•
작업 단위로 트랜잭션 업그레이드하기
◦
레포지터리와 트랜잭셔을 도입하면 잠재적인 데이터 모순을 피할 수 있지만 더 좋은 방법이 있다. 트랜잭션 클래스를 작업 단위로 업그레이드하는 것이다.
▪
작업 단위에는 비즈니스 연산의 영향을 받는 객체 목록이 존재한다.
▪
작업이 완료되면 작업 단위는 데이터베이스를 변경하기 위해 해야하는 업데이트를 모두 파악하고 이러한 업데이트를 하나의 단위로 실행한다.
◦
일반 트랜잭션과 비교해 작업 단위가 갖는 가장 큰 장점은 업데이트 지연이다. 트랜잭션과 달리 작업 단위는 비즈니스 연산 종료 시점에 모든 업데이트를 수행하므로 트랜잭션의 기간을 단축하고 데이터 혼잡을 줄인다.
◦
실제로는 이러한 작업을 직접 할 필요가 없다. 대부분의 ORM 라이브러리가 작업 단위 패턴을 구현한다.
2.
통합 테스트에서 데이터베이스 트랜잭션 관리하기
•
통합 테스트에서 데이터베이스 트랜잭션을 관리해야하는 경우, 다음 지침을 준수하라.
◦
테스트 구절 간에 데이터베이스 트랜잭션이나 작업 단위를 재사용하지 말라.
3. 테스트 데이터 생명 주기
•
공유 데이터베이스를 테스트에 사용하면 통합 테스트를 서로 분리하 수 없는 문제가 생긴다. 이를 해결하려면 다음과 같은 방법들이 있다.
◦
통합 테스트를 순차적으로 실행하라.
◦
테스트 실행 간에 남은 데이터를 제거하라.
•
테스트는 데이터베이스 상태에 영향을 받아선 안 된다. 테스트는 데이터베이스 상태를 원하는 조건으로 만들어야 한다.
1.
병렬 테스트 실행과 순차적 테스트 실행
•
통합 테스트를 병렬로 실행하려면 노력이 필요하다. 모든 테스트 데이터가 고유한 상태인지 확인해야 데이터베이스 제약 조건을 위반하지 않고 테스트 간 영향을 끼치는 일이 없다.
◦
실행 후 남은 데이터를 처리하는 것도 까다롭다. 성능 향상을 위해 테스트 작성에 시간을 허비하지 않고 순차적으로 통합 테스트를 실행하는 것이 실용적이다.
◦
통합 테스트 군은 테스트 병렬 처리를 비활성화하라.
•
대안으로 컨테이너를 사용해 테스트를 병렬 처리할 수도 있다. 모델 데이터베이스를 도커 이미지로 만들고 각 통합 테스트 별로 해당 이미지에서 새 컨테이너를 인스턴스화할 수 있다.
◦
이 방식은 유지보수 부담이 너무 커지게 된다. 다음과 같은 작업들이 뒤따라야하기 때문이다.
▪
데이터베이스 이미지를 지속적으로 동기화시켜주어야 한다.
▪
도커 이미지를 유지보수해주어야 한다.
▪
각 테스트마다 컨테이너 인스턴스가 정상적으로 동작하는지 확인해야 한다.
▪
다 사용한 컨테이너는 종료시켜주어야 한다.
•
통합 테스트의 실행 시간을 극한으로 줄이고 싶지 않다면 컨테이너를 사용하지 않는 것이 좋다.
•
다시 말하자면 데이터베이스는 개발자당 하나의 인스턴스만 갖는 것이 더 실용적이다.
2.
테스트 실행 간 데이터 정리
•
테스트 실행 후 남은 데이터를 정리하는 방법은 네 가지가 있다.
◦
각 테스트 전에 데이터베이스 백업 복원하기
▪
다른 세 방법보다 훨씬 느린 방법으로 테스트 스위트 실행 시간이 빠르게 늘어난다.
◦
테스트 종료 시점에 데이터 정리하기
▪
빠르지만 정리 단계를 건너뛰기 쉽다. 테스트 도중 빌드 서버가 중단되거나 디버거에서 테스트를 종료하면 입력 데이터가 데이터베이스에 남아있게 되고 이후 테스트 실행에 영향을 주게된다.
◦
데이터베이스 트랜잭션에 각 테스트를 래핑하고 커밋하지 않기
▪
이 경우, 테스트와 SUT에서 변경한 내용이 자동으로 롤백된다.
▪
이 접근 방식은 정리 단계를 건너뛰는 문제를 해결하지만 또 다른 문제를 제기한다.
◦
테스트 시작 시점에 데이터 정리하기
▪
이 방법이 가장 좋다. 빠르게 작동하고 일관성없는 동작이 일어나지 않으며 정리 단계를 실수로 건너뛰지 않는다.
•
데이터베이스의 경우, 구조를 이해하기 쉽게 외래키가 존재하는 경우가 있다. 이런 제약조건을 준수하려면 특정 순서에 따라 데이터를 제거해야 한다.
◦
어떤 사람들은 정교한 SQL 설계를 통해 테이블 간의 관계를 파악하고 자동으로 삭제 스크립트를 생성하기도 하며 모든 무결성 제약 조건을 비활성화한 후 삭제했다가 다시 활성화시키기도 한다.
◦
하지만 이는 불필요하다. SQL 스크립트를 수동으로 작성하면 더 간단하고 삭제 프로세스를 세밀하게 제어할 수 있다.
•
모든 통합 테스트의 기초 클래스를 두고 기초 클래스에 삭제 스크립트를 작성하라. 이렇게 기초 클래스를 사용하면 테스트가 시작될 때마다 스크립트가 자동으로 실행되도록 할 수 있다.
3.
인메모리 데이터베이스 피하기
•
통합 테스트를 서로 분리하는 방법으로는 h2 데이터베이스와 같은 메모리 데이터베이스로 교체할 수도 있다. 이는 다음과 같은 장점을 가진다.
◦
테스트 데이터를 제거할 필요가 없음
◦
작업 속도 향상
◦
테스트가 실행될 때마다 인스턴스화 가능
•
인메모리 데이터베이스는 공유 의존성이 아니기 때문에 앞서 설명한 컨테이너 접근 방식과 유사한 단위 테스트가 된다.
•
이는 일반 데이터베이스와 기능적 일관성이 없기 때문에 사용하지 않는 것이 좋다.
◦
이는 또 다시 운영 환경과 테스트 환경이 일치하지 않는 문제를 야기하며 데이터베이스 간 차이(문법 등)으로 인해 거짓 양성이나 거짓 음성이 발생하기 쉽다.
테스트에서도 운영 환경과 같은 데이터베이스를 사용하라
4. 테스트 구절에서 코드 재사용하기
•
통합 테스트가 너무 빠르게 커지면 유지보수 지표가 나빠질 가능성이 존재한다.
•
통합 테스트는 가능한 짧게 하되 서로 결합하거나 가독성에 영향을 주지 않도록 하는 것이 중요하다.
◦
아무리 짧은 테스트라도 서로 의존해서는 안 된다. 또한 테스트 시나리오의 전체 맥락을 유지해야 하며 진행 상황을 이해하고자 테스트의 다른 영역을 확인해서는 안 된다.
•
통합 테스트를 짧게 하기에 가장 좋은 방법은 비즈니스 로직과는 상관 없는 부분을 비공개 메서드나 헬퍼 클래스로 추출하는 것이다. 더구나 그 부분은 재사용될 수 있다.
•
이 절에서는 테스트의 Arrange, Act, Assert를 어떻게 줄여야하는 지 알아본다.
1.
준비 구절에서 코드 재사용하기
•
사용자가 필요할 때, 사용자를 생성하는 로직을 비공개 정적 팩토리 메소드로 생성한다던지 더미 데이터 등이 필요할 때 헬퍼나, 비공개 메소드로 생성할 수 있다.
•
팩토리 메소드는 어디에 둬야할까? 일단은 단순하게 해당 메소드가 필요한 클래스 내부에 위치시키자.
◦
만약 다른 클래스에서도 사용하게 된다면 헬퍼 클래스로 이동시키자.
•
기초 클래스에 팩토리 메소드를 넣지 말라 기초 클래스는 데이터 정리와 같이 모든 테스트에서 공통적으로 실행될 수 있는 코드만 남겨두어야 한다.
2.
실행 구절에서 코드 재사용하기
•
모든 통합 테스트의 실행 구절에서는 트랜잭션이나 작업 단위를 생성한다.
•
실행 구절도 줄일 수 있다. 어떤 컨트롤러 기능을 호출해야 하는지에 대한 정보를 담고 있는 대리자를 받는 메소드를 도입할 수 있다.
◦
흠.. 추출을 하자면 이런식으로 하자는 것 같다. 테스트 단의 가독성이 좋아지니까..!
3.
검증 구절에서 코드 재사용하기
•
가장 쉬운 방법은 헬퍼 메소드를 두는 것이다.
•
데이터 검증을 위한 플루언트 인터페이스를 만들 수 있다.
◦
이건 잘 모르겠다. 데이터 검증은 도메인의 영역이라고 생각해서.. 이건 검증 구절에서 제공해주는 assert문으로 처리하는 게 낫지 않을까?
4.
테스트가 데이터베이스 트랜잭션을 너무 많이 생성하는가?
•
통합 테스트를 간결하게 하면 더 읽기 쉽고 유지보수하기에도 용이해진다. 그러나 데이터베이스 트랜잭션을 여러개 사용하게된다는 단점이 생긴다.
•
트랜잭션 수가 늘면 테스트가 느려지기 때문에 성능이 저하된다. 하지만 성능보다 더 중요한 것은 유지보수성이다. 우린 이미 관리 의존성 데이터베이스를 통합 테스트에 포함시킴으로써 성능을 어느정도 포기했다.
5. 데이터베이스 테스트에 대한 일반적인 질문
1.
조회에 대한 테스트를 해야 하는가?
•
이 책에서 다룬 대부분의 테스트는 명령에 대한 테스트였다.
◦
대부분의 어플리케이션엔 명령과 조회 작업이 모두 존재하는데, 조회 작업을 테스트해야하는가?
•
명령을 철저히 테스트하는 것은 매우 중요하다. 위험성이 높기 때문인데, 명령 작업이 잘못되면 데이터가 손상되어 데이터베이스뿐만 아니라 외부 어플리케이션에도 이런 문제가 전파될 수 있다.
•
조회는 이에 해당하지 않는다. 조회 작업의 버그에는 보통 해로운 문제가 없다. 따라서 가장 복잡하거나 중요한 조회 작업만 테스트하고 나머지는 무시하라.
•
조회에는 추상화 계층이 거의 없기 때문에 단위 테스트가 아무 소용이 없다. 조회를 테스트하기로 결정한 경우에는 실제 데이터베이스에서 통합 테스트를 하는 것이 낫다.
2.
레포지터리 테스트를 해야 하는가?
•
레포지터리는 데이터베이스와 어플리케이션 간에 유용한 추상화 계층을 제공한다.
•
이는 관리 의존성이므로 이를 테스트에 포함시키게될 경우, 높은 유지비와 낮은 회귀 방지라는 단점을 제공하게 된다.
•
가급적이면 하지 않는 것이 좋다.
•
레포지터리는 가급적이면 통합 테스트 스위트의 일부로 두는 것이 좋다.
6. 결론
•
데이터베이스 테스트를 잘 만들면 회귀 방지를 잘하는 테스트 코드를 작성할 수 있다.
◦
이러한 테스트는 데이터베이스를 리팩토링하거나 ORM으로 전환, 데이터베이스를 변경할 때, 큰 도움이 된다.
•
관리 의존성에 직접 작동하는 통합 테스트는 대규모 리팩토링에서 발생하는 버그로부터 보호하기에 가장 효율적인 방법이다.
요약
•
데이터베이스 스키마를 소스 코드와 같이 형상 관리 시스템에 저장하라.
◦
테이블, 뷰, 인덱스, 저장 프로시저와 데이터베이스 구성 방식에 대한 청사진이 되는 기타 모든 항목 등이 데이터베이스 스키마에 해당한다.
•
참조 데이터도 데이터베이스 스키마에 해당한다. 이는 어플리케이션이 제대로 작동하도록 미리 채워져야하는 데이터다.
◦
참조 데이터와 일반 데이터를 구별하려면 어플리케이션에서 해당 데이터를 수정할 수 있는지 확인하면 된다. 수정할 수 있으면 일반 데이터고 불가하다면 참조 데이터다.
•
개발자마다 데이터베이스 인스턴스를 따로 두도록하라.
◦
더 좋은 방법은 각 로컬에 인스턴스를 호스팅하는 것인데, 이렇게하면 피드백 속도를 극대화할 수 있다.
•
데이터베이스 배포 방식엔 두 가지가 있는데 다음과 같다.
◦
상태 기반 데이터베이스 배포 방식은 상태를 명시적으로 만들고 비교 도구가 마이그레이션을 암묵적으로 제어할 수 있다.
◦
마이그레이션 기반 방식은 데이터베이스를 특정 상태에서 다른 상태로 전환하게끔 명시적 마이그레이션을 사용하도록 한다.
◦
데이터베이스 상태가 명확하면 병합 충돌을 좀 더 쉽게 처리할 수 있는 데 반해, 명시적 마이그레이션은 데이터 모션 문제를 해결하는 데 도움이 된다.
•
저자는 상태 기반 방식보다는 마이그레이션 방식을 선호한다.
◦
데이터 모션 처리가 병합 충돌보다 훨씬 중요하기 때문이다. 마이그레이션을 통해 모든 수정 사항을 데이터베이스 스키마에 적용하라.
•
비즈니스 연산은 데이터를 원자적으로 업데이트해야 한다. 원자성을 얻으려면 데이터베이스 트랜잭션 매커니즘에 의존하라.
•
가능하면 작업 단위 패턴을 사용하라. 작업 단위는 데이터베이스 트랜잭션에 의존하며 비즈니스 연산 종료 시점까지 업데이트를 지연시켜서 성능을 향상시킨다.
•
테스트 구절마다 데이터베이스 트랜잭션을 따로 두도록하라. 준비, 실행, 검증 구절에 각각 고유의 트랜잭션이나 작업 단위가 있어야 한다.
•
통합 테스트는 순차적으로 실행하라. 병렬 실행에는 상당한 노력이 필요하며, 보통 그럴 가치가 없다.
•
테스트 시작 시점에 데이터를 정리하라. 이 방식은 빠르고 일관성 없는 동작을 발생시키지 않으며 정리 단계를 실수로 건너뛰지 않는다. 이 경우 별도의 빌드 단계도 필요없다.
•
인메모리 데이터베이스는 사용하지 말라. 테스트도 운영 환경과 같이 동일한 DBMS를 사용하는 것이 좋다.
•
비즈니스 로직의 핵심이 아닌 부분들은 비공개 메소드 또는 헬퍼 클래스로 추출해 테스트를 단축하라.
◦
준비 구절에서는 테스트 데이터 빌더 대신 오브젝트 마더를 선택하라
◦
실행 구절에서는 데코레이터 메소드를 작성하라
◦
검증 구절에서는 플루언트 인터페이스를 도입하라
•
조회 테스트는 명령 테스트보다 그 중요성이 낫다. 따라서 복잡하거나 중요한 조회 작업만 테스트하라. 나머지는 무시하라.
•
레포지터리는 따로 테스트하지 말고 포괄적인 통합 테스트 스위트로 취급하라.
◦
레포지터리 테스트는 회귀 방지에 대한 이득보다 유지 보수 비용이 너무 높다.