※ 작성 당시에는 좋은 방법이라고 생각했는데, 지금은 통합 테스트를 하는데 Repository를 Fake로 치환하는 것은 좋지 않다고 생각합니다. 그래도 dev 환경과 product 환경에서 다른 클래스를 사용해야 한다면 쓸만한 방법인 것 같아 글은 지우지 않았습니다.
@SpringBootTest를 사용해서 통합 테스트를 진행 중이다. 그런데 테스트에서 TargetReository 인터페이스를 구현하는 RealRepository가 무겁고 세팅도 번거롭다. 그래서 가벼운 FakeRepository로 대체해서 테스트를 진행하고자 한다.
여기서 RealRepository는 @Component를 붙여서 자동으로 Bean 등록된다.
TargetRepository 인터페이스
public interface TargetRepository {
void save(String key, String value);
String get(String key);
void delete(String key);
}
RealRepository 클래스
@Component
public class RealRepository implements TargetRepository {
Map<String, String> map = new HashMap<>();
@Override
public void save(String key, String value) {
System.out.println("RealRepository.save");
map.put(key, value);
}
@Override
public String get(String key) {
System.out.println("RealRepository.get");
return map.get(key);
}
@Override
public void delete(String key) {
System.out.println("RealRepository.delete");
map.remove(key);
}
}
먼저 RealRepository를 사용해서 테스트를 진행했다.
@SpringBootTest
class RealRepositoryTest {
@Autowired
TargetRepository targetRepository;
@Test
public void realTest() {
String key = "key";
String value = "value";
targetRepository.save(key, value);
assertThat(targetRepository.get(key)).isEqualTo(value);
targetRepository.delete(key);
assertThat(targetRepository).isInstanceOf(RealRepository.class);
}
}
/* 출력
RealRepository.save
RealRepository.get
RealRepository.delete
*/
이제 RealRepository를 대체하는 FakeRepository로 바꿔서 테스트를 진행해 보자.
FakeRepository 클래스는 Test 폴더에 구현했고 자동 빈 등록은 하지 않았다. 그리고 @Primary를 붙여서 DI 우선순위를 높였다.
FakeRepository 클래스
@Primary
public class FakeRepository implements TargetRepository {
Map<String, String> map = new HashMap<>();
@Override
public void save(String key, String value) {
System.out.println("FakeRepository.save");
map.put(key, value);
}
@Override
public String get(String key) {
System.out.println("FakeRepository.get");
return map.get(key);
}
@Override
public void delete(String key) {
System.out.println("FakeRepository.delete");
map.remove(key);
}
}
이제 대체된 FakeRepository로 테스트를 진행해 보자.
@SpringBootTest
@Import(FakeRepository.class)
public class FakeRepositoryTest {
@Autowired
TargetRepository targetRepository;
@Test
public void fakeTest() {
String key = "key";
String value = "value";
targetRepository.save(key, value);
assertThat(targetRepository.get(key)).isEqualTo(value);
targetRepository.delete(key);
assertThat(targetRepository).isInstanceOf(FakeRepository.class);
}
}
/* 출력
FakeRepository.save
FakeRepository.get
FakeRepository.delete
*/
@Import로 FakeRepository도 Bean으로 등록을 했다. 그러면 targetRepository에 주입되는 Bean 대상은 RealRepository와 FakeRepository가 되는데, @Primary가 붙은 FakeRepository가 의존성 주입 우선순위가 높아서 FakeRepository가 주입된다.
@Profile, @ActiveProfile을 사용해도 이와 비슷하게 테스트가 가능하지만, @Primary를 사용한 방법이 RealRepository 코드를 @Profile를 붙여서 수정할 필요도 없이 깔끔하고 간단했다.
대신 @Profile을 사용한 방법과 달리 RealRepository와 FakeRepository가 둘 다 Bean으로 등록되니 TargetRepository로 추상화해서 작성한 코드가 아니면 RealRepository가 그대로 주입되는 건 주의해야겠다.
'Test' 카테고리의 다른 글
단위 테스트 - 마틴 파울러 (0) | 2023.02.15 |
---|---|
Test 용어 정리 (0) | 2023.02.14 |
테스트 관련 사이트 (0) | 2023.02.14 |