어떤 개념인가요 ?

테스트를 할 때 계층별로 기준을 어디서부터 어디까지 나눠야 할지에 대해서 항상 생각을 많이 하는거 같다. 이 중에서 Service 통합테스트에 대해서 생각을 해보려고 한다. Service 통합테스트를 작성한다면 Repository 테스트는 필요가 없을까? 에 대한 질문이다.

이런 질문이 왜 나오게 되었는지를 먼저 생각해보면 Service 통합테스트가 내부적으로 Repository를 거치니까, Repository 테스트는 중복이 되는거 아닌가?라는 질문을 하게 된다.

하지만 여기서 두가지 테스트는 구분을 해보면 다음과 같습니다.

  • Repository 테스트의 경우 데이터 접근 계층으로써 쿼리, 매핑, 제약조건 등이 의도대로 동작하는지 검증하고,
  • Service 통합테스트에서는 비즈니스 로직이 여러 컴포넌트를 거치고 나서 올바른 결과들을 내는지를 검증한다.

왜 이런 생각을 하게 되었을까?

테스트는 코드에 대한 보호에 대해서 신뢰를 주는 만큼, 작성과 유지에 대한 비용도 많이 든다고 생각합니다.

그래서 모든 계층을 다 테스트 해야하나, 아니면 상위 테스트로 하위를 커버할 수 있나? 라는 효율적인 잔머리를 생각하게되는거 같습니다.

결론은 그 비용 대비 효용의 경계를 어디에 둘지 정하려는 문제의식에서 나온 질문이라고 생각이 들었다.

어떤 흐름인가?

Service 통합테스트는 Service를 진입점으로 시작해서 Repository와 DB까지 함께 띄워 검증하게 됩니다. 따라서 Service를 통해 호출되는 Repository 경로는 자연스럽게 같이 실행이된다.

하지만, Service가 호출된든 것은 Repository의 기능의 일부일 뿐이다.

예를 들어서, Service에서는 findById만 사용하지만, Repository에서는 복잡한 조건 검색, 정렬, 페이징, 커스텀 쿼리(JPQL, QueryDSL)가 더 존재할 수 있다.

즉, Service 테스트만으로는 이러한 Repository에서의 나머지 쿼리들일 검증되지 않는다.

언제 Repository 테스트를 쓰고 안쓸까?

Repository 테스트를 따로 작성할 때:

  • 직접 작성한 쿼리들 (@Query, JPQL, QueryDSL, native query)이 존재할 때, 자동 생성되지 않는 로직이라서 별도 검증이 필요하다.
  • 복잡한 조건/정렬/페이징, 연관관계 매핑, fetch join, N+1과 같은 영속성 동작을 검증하고 싶을 때?
  • DB 제약 조건 (unique, not null, FK)이나 동시성 관련 동작들을 테스트하고 싶을 때
  • Service에서 호출하지 않는 Repository메서드가 존재할 때

Repository 테스트를 생략해도 무방할 때:

  • Repository가 기본적으로 Spring Data JPA에서 제공하는 기본 메서드만 사용할 때, 이건 프레임워크가 보장하는 영역이라서, 내 코드가 아니라 프레임워크를 테스트하는 셈이 된다.
  • Service 통합테스트가 해당 Repository 경로를 충분히 커버하고 있고, 추가 검증할 커스텀 로직이 존재하지 않을 때

남에게 설명한다면 어떻게 설명할 것인가?

Service 통합테스트가 Repository를 거쳐가기 때문에 Repository 테스트가 필요가 없다는 생각을 하게 되었다고 생각이 들었습니다.

이 말을 반은 맞고 반은 틀린 생각이라고 생각합니다.

Repository 테스트는 세부적으로 더 작은 Service에서 사용하는 부품들에 대한 테스트를 진행하는 것이고, Service 통합테스트는 그 부품들을 끼워서 만든 기계가 작동이 되는지를 보는 것이라고 생각한다. 하지만, 그것은 정해진 동작에서만의 기능을 검증하는 것이라고 생각한다. 즉, 부품의 모든 세부 성능에 대한 테스트까지 필요할까? 라는 생각을 해보았을 때, 필요하다면, Repository 테스트를 작성하는 것이 맞다고 생각합니다.

결론적으로, Repository에서 세부 부품들에 더 작성하거나 신경을 써서 만든 부분이 존재거나, 직접 작성한 쿼리가 있다면 Repository 테스트는 따로 필요하다고 생각한다


추가 궁금한 질문들