GitHub

https://github.com/Choidongjun0830

우테코

데이터베이스에 종속되지 않는 Repository 테스트를 작성할 수는 없을까?

gogi masidda 2025. 6. 4. 11:25

JDBC에서 JPA로 전환하며 느낀 테스트 설계의 고민

이 고민은 방탈출 예약 대기 미션으로 넘어오면서 시작되었다.
요구사항 중 하나는 기존 JDBC 기반의 구현을 Spring Data JPA로 전환하는 것이었다.
전환 이후, 이전에 작성해둔 테스트 코드들이 대거 실패하면서 꽤나 당황스러운 경험을 했다.
물론, 테스트를 처음부터 깔끔하게 설계하지 못한 내 책임도 있었겠지만, JdbcTemplate에서 EntityManager로 바뀐 기술 간의 차이 역시 그 원인 중 하나였다.

이러한 경험은 나에게 새로운 질문을 던지게 했다:
“Spring Data JPA를 쓰는데, Repository 테스트를 굳이 작성해야 할까?”

 

내가 선택한 방향

처음에는 고민이 많았다.
하지만 레벨 2 수업 시트에서 @DataJpaTest라는 힌트를 보고, JPA 기반 Repository 테스트를 일단 작성해보기로 했다.

테스트는 크게 두 종류로 나뉘었다.

  • Query Method 기반 메서드
    Spring Data JPA가 자동 구현하는 메서드
  • @Query 기반 JPQL/SQL 메서드
    직접 쿼리를 작성한 복잡 로직

단순한 CRUD는 테스트하지 않았고, 위와 같은 “내가 작성한 로직이 포함된 쿼리”만 테스트 대상으로 삼았다.
하지만 테스트를 작성할수록 고민이 들었다.
“정말 모든 메서드를 테스트하지 않아도 괜찮을까?”
이 고민의 바닥에는 Repository 테스트를 왜 작성하는가라는 근본적인 질문이 있었다.

 

테스트의 목적은 무엇인가?

만약 JPA 자체의 기능을 믿는 것이 목적이라면, Query Method는 굳이 테스트하지 않아도 될 것이다.
그러나 내가 설정한 테스트의 목적은 달랐다.

“데이터베이스 접근 기술(JDBC → JPA → 다른 기술)이 바뀌더라도, Repository가 여전히 내가 원하는 동작을 하는지를 검증하고 싶다.”

즉, 내가 만든 추상화가 바뀐 구현체에서도 동일하게 작동하는지 확인하고 싶었다.
이는 결과적으로 Service가 데이터베이스 기술에 종속되지 않고, 변경에도 안정성을 유지하는 기반이 된다.

 

데이터베이스에 종속되지 않는 Repository 테스트를 위해 필요한 것

데이터베이스에 종속되지 않는 테스트와 Service에서의 변경을 최소화하는 것은 공통의 목적을 공유한다고 생각한다.

  • Service는 특정 기술(JPA, JDBC)에 의존하면 안 된다.
    → 인터페이스 추상화(MemberRepository)를 두고 구현체에서 기술을 캡슐화해야 한다.
  • Repository 구현체는 Service 입장에서 행위만 보장하면 된다.
    → 어떤 기술로 구현되었든 상관없이 “동일한 결과”를 내는 것이 중요하다.

 

내가 작성한 테스트

@ActiveProfiles("test")
@DataJpaTest
class JpaMemberRepositoryTest {

    @PersistenceContext
    private EntityManager entityManager;

    @Autowired
    private MemberRepository memberRepository;

    @Test
    void findByEmail() {
        //given
        Member member = TestFixture.createDefaultMember();
        entityManager.persist(member);

        //when
        Optional<Member> result = memberRepository.findByEmail(member.getEmail());

        //then
        assertThat(result.isPresent()).isTrue();
        assertThat(result.get().getEmail()).isEqualTo(member.getEmail());
    }
}

 

이 테스트는 완전히 독립적인가?

  • MemberRepository 인터페이스를 통해 검증하므로 행위 기준으로는 기술 독립적이다.
  • 하지만 @DataJpaTest, EntityManager 사용은 기술 종속적이다.
    → 기술이 변경되면 @JdbcTest, JdbcTemplate으로 다시 작성해야 한다.

그렇다면 테스트 준비 과정(given)에 사용하는 entityManager.persist()를 memberRepository.save()로 바꾸면 기술 종속성을 줄일 수 있을까?

가능은 하지만, save() 자체도 테스트 대상이기 때문에 “검증되지 않은 것을 검증에 사용한다”는 문제가 생긴다.
결국, 하나의 메서드를 검증하기 위해 또 다른 검증되지 않은 메서드를 사용하는 것은 위험할 수 있다고 생각한다.

다른 테스트에서 충분한 검증이 이루어지면 괜찮겠지만, 아직은 충분함의 기준도 모르겠다.

 

결론

데이터베이스 접근 기술에 완전히 독립적인 Repository 테스트를 작성하는 것은 쉽지 않다.

  • 테스트 환경(@DataJpaTest, @JdbcTest)
  • 테스트 준비 코드(EntityManager, JdbcTemplate)
    이 모두가 기술에 종속되기 때문이다.

하지만 Repository 인터페이스 기준으로 테스트 대상을 삼고, 기술은 내부로 감추었다면, 우리는 기술 변경에 영향을 덜 받는 구조를 설계한 것이다.
궁극적으로는 테스트의 기술 독립성보다는 Repository의 계약이 보장되는지를 검증하는 데 집중하는 것이 더 현실적인 목표라고 생각한다.

728x90

'우테코' 카테고리의 다른 글

우테코 레벨 2까지의 회고  (5) 2025.06.13
우테코에서의 6주차 WIL  (0) 2025.03.25
우테코에서의 5주차 WIL  (0) 2025.03.17
우테코에서의 4주차 WIL  (0) 2025.03.09
우테코에서의 3주차 WIL  (0) 2025.03.06