Basics: build, operate, check#
- 모든 통합테스트는 build, operate, check 단계를 가진다.
- build: 테스트 시나리오를 준비하는 단계. 일반적으로 데이터에비스에 데이터를 추가한다.
- operate: 테스트할 API나 객체의 메서드를 호출한다.
- check: 실행한 API나 메서드의 결과가 예상한대로 동작했는지 확인한다.
build 단계: 데이터 추가#
- build 단계에 테스트 시나리오를 위해 데이터베이스에 데이터를 추가해야된다.
- 데이터를 추가하는 방법으로는 3가지가 있다.
- 테스트 중인 시스템의 API 호출
- 순수 SQL 사용
- Repository Layer 사용
테스트 중인 시스템의 API 호출#

- 이는 안티패턴이 될 수 있다.
- build 단계에서 테스트 실패가 발생할 수 있다.
- 테스트가 실패하면 build 단계에서 실패했는지, operate 단계에서 실패했는지 확인을 해봐야된다.
- build 단계에서 호출한 API가 수정이 되었을 때, 이로인해 테스트가 실패로 바뀔 수 있다.
순수 SQL 사용#

- 테스트 중인 시스템의 API를 호출할 때 발생하던 문제는 해결된다.
- 하지만, 프로덕트 코드에서 ORM을 사용하고 있다면, ORM에서 제공하는 기능을 모두 테스트 코드에서 구현해야된다.
Repository Layer 사용#

- ‘테스트 중인 시스템의 API 호출’ 과 비슷해보일 수 있지만, 애플리케이션 API를 호출하는 것이 아닌 Repository 레이어를 사용하는 방법이다.
- 애플리케이션은 일반적으로 최소 2, 3개 레이어로 구성되는데 레이어가 추가될수록 버그가 발생할 확률이 높다.
- DB와 가장 인접한 Repository Layer를 사용해서 버그가 발생할 확률을 낮출 수 있다.
build 단계: 엔티티 생성#
- 일반적으로 테스트 코드에서 엔티티를 생성할 때, 코드 중복을 막기 위해서 팩토리 메서드를 만들어서 호출한다.
- 아래 코드에서
createDefault
와 createDefaultUserAccount
가 팩토리 메서드다.
//BUILD
Organization organization = createDefault();
organizationRepository.save(organization);
User user = createDefaultUserAccount(organization);
userAccountRepository.save(organisation);
//OPERATE
client.updateUserAccount(updateRequest);
//CHECK
user = userAccountRepository.getUserAccount(user.getId());
assertUser(updateRequest, user);
- 하지만 팩토리 메서드는 문제점이 있다.
- 테스트 케이스가 많아질수록 같은 엔티티에 대한 팩토리 메서드가 점점 늘어난다.
- 팩토리 메서드가 위치해야 되는 곳에 대한 고민이 생긴다.
- 빌더 패턴을 사용해서 이를 해결할 수 있다.
check 단계: Assertion#
- check 단계에서 응답 DTO와 엔티티를 비교해서 테스트하는 경우가 있다.
- 테스트 케이스가 늘어나면서 이 비교를 그대로 복사-붙여넣기 해서 사용하거나, 공통적인 부분을 메소드로 추출하기도 한다.
- 엔티티 빌더와 비슷하게 Assertion 로직도 별도의 클래스로 만들어 둘 수 있다.