////
Search
Duplicate
🚄

10. 데이터베이스 테스트

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를 사용하는 것이 좋다.
비즈니스 로직의 핵심이 아닌 부분들은 비공개 메소드 또는 헬퍼 클래스로 추출해 테스트를 단축하라.
준비 구절에서는 테스트 데이터 빌더 대신 오브젝트 마더를 선택하라
실행 구절에서는 데코레이터 메소드를 작성하라
검증 구절에서는 플루언트 인터페이스를 도입하라
조회 테스트는 명령 테스트보다 그 중요성이 낫다. 따라서 복잡하거나 중요한 조회 작업만 테스트하라. 나머지는 무시하라.
레포지터리는 따로 테스트하지 말고 포괄적인 통합 테스트 스위트로 취급하라.
레포지터리 테스트는 회귀 방지에 대한 이득보다 유지 보수 비용이 너무 높다.