테스트 격리

YAHO·2022년 7월 27일
1

Spring

목록 보기
1/1
post-thumbnail

테스트 격리

🧐 테스트 격리란?

  • 테스트가 순서에 상관없이 독립적으로 실행되며 결정적으로 수행되야 함

  • 같은 입력 값이면 언제나 어떤 순서라도 같은 결과를 반환해야 함

  • 멱등하다는 의미도 포함하고 있음

🤔 테스트를 왜 격리해야 하는가?

내가 느낀 이유

  • 새로운 테스트가 기존 테스트에 영향을 주지 않게하기 위해서

검색을 통해 알게된 이유

  • 테스트들이 서로 순서에 상관 없이 독립적으로 수행되어야 하기 때문에

  • 마틴 파울러는 비결정적 테스트의 문제점에 대해 언급하며 그 원인으로 테스트 격리의 부족을 이야기했다고 함

    • 비결정적 테스트가 뭘까?? ❓

🤨 계층별 테스트 격리 방법

domain

  • 테스트 격리가 필요 없음

    • 서로 다른 테스트에서같은 객체를 사용하지 않도록 하거나

    • 공통 fixture를 사용할 경우 @BeforeEach 를 사용해 초기화

repository

  • @DataJpaTest

    • 데이터 계층에 관련된 빈들만 가지고 slice 테스트

      • slice 테스트란? ❓
    • DB에 접근하기는 함

    • 해당 어노테이션을 사용하면 InMemory에서 실행되며 자동으로 @Transactional 어노테이션이 적용됨

      • InMemory가 뭐지? ❓

      • @Transactional 이란? ❓

service

  • @Transactional

    • 기본전략이 트랜잭션 rollback

    • 실제로는 데이터베이스의 상태를 변화시키지 않고 격리된 상황에서 테스트

  • Mock 프레임워크

    • 실제 DB 근처에는 접근도 하지 않음

    • 테스트 격리를 신경쓰지 않고 테스트할 수 있음

    • Mock 프레임워크가 뭐지? ❓
      💡hint: Mockito…

controller

  • Mock 프레임워크

    • MockMvc : Rest API 클라이언트 도구

    • @SpringBootTest vs @WebMvcTest ❓
      💡hint: @WebMvcTest는 @DataJpaTest와 마찬가지로 해당 계층에 관련된 빈들만 가지고 slice 테스트 가능

인수 테스트

  • @Transactional

    • 인수 테스트에서는 사용할 수 없는 방법

    • @SprintBootTest 에서는 port 를 지정해 서버를 띄움

    • 이때 HTTP 클라이언트와 서버는 각각 다른 스레드에서 실행됨

    • 따라서 호출되는 쪽은 다른 트랜잭션으로 커밋되기 때문에 해당 어노테이션이 무의미함

  • DELETE query

    • @BeforeEach에서 테스트에 필요한 데이터를 생성하고 @AfterEach에서 데이터 삭제 요청을 보내는 방법

    • 테스트에 필요한 데이터가 적은 경우 용이할 수 있음

    • 하지만 필요한 데이터의 양이 많거나, 연관관계가 복잡한 경우 굉장한 비효율이 발생할 수 있음

  • TRUNCATE query

    • 매 테스트 이후 모든 테이블을 초기화하는 방법

      • DELETE vs TRUNCATE ❓

      • DELETE query에 비해 좋은 이유

      • JPA의 경우 DELETE 요청이 오면 바로 DELETE를 하는 것이 아니라 SELECT로 조회 후 DELETE를 함

        • 왜? ❓
      • 삭제를 수행할 때 트랜잭션 로그 공간을 적게 사용

      • DELETE는 행마다 lock을거는데 비해 TRUNCATE은 lock을 거는 수가 상대적으로 적은 시간에 테이블 초기화

        • lock이 뭐지? ❓
      1. @Sql 사용
      • 스프링부트에서 제공하는 어노테이션

      • 클래스 테스트가 실행되기 전에 @Sql이 가리키는 경로에 있는 SQL 실행이 먼저 일어남

      • 따라서 이 파일안에 모든 테이블에 대한 TRUNCATE SQL을 미리 작성

      • 하지만 엔티티 또는 연관관계 테이블이 추가될 때마다 파일을 수정해줘야 하는 단점이 있음

      1. EntityManager 사용
      • JPA에서 쿼리를 직접 만들 수 있는 EntityManager를 빈으로 주입

      • 모든 테이블 이름을 조사해서 각각의 인수테스트가 시작할 때 TRUNCATE 쿼리를 실행시키는 방식

  • @DirtiesContext

    • 현재 테스트가 실행되려는 컨텍스트에 이미 빈이 올라가 있으면 Dirties를 확인하고 컨텍스트를 새로 로드하는 방법

    • 하지만 매번 테스트 하기전에 컨텍스트를 다시 로드하게 되면 테스트하는데 시간이 오래걸림

profile
야호!

0개의 댓글