1주차 인수테스트 코드에서의 팁

PPakSSam·2022년 1월 23일
0
post-thumbnail
post-custom-banner

인수테스트 코드에서 알아두면 좋은 개념

1. @SpringBootTest

  • 테스트에 사용할 ApplicationContext를 쉽게 지정하게 도와준다.
  • 기존 @ContextConfiguration의 발전된 기능
  • SpringApplication에서 사용하는 ApplicationContext를 생성해서 작동한다.

2. @webEnvironment

@SpringBootTest의 webEnvironment 속성을 사용하여 테스트 서버의 실행 방법을 설정

  • MOCK : Mocking된 웹 환경을 제공, MockMvc를 사용한 테스트를 진행할 수 있다.
  • RANDOM_PORT : 실제 웹 환경을 구성
  • DEFINED_PORT : 실제 웹 환경을 구성, 지정한 포트를 사용한다.
  • NONE : 아무런 웹 환경을 구성하지 않는다.

MOCK의 경우는 @Transactional을 사용할 수 있다.
그러나 RANDOM_PORT의 경우 싱글스레드가 아니라 클라이언트와 서버가 분리되어 있다.
즉, 멀티 스레드 환경이므로 @Transactional을 사용할 수 없다.

3. RestAssured

RESTAssured는 REST API의 테스트 및 검증을 단순화하도록 설계되었다.
HTTP 작업에 대한 검증을 위한 풍부한 API를 활용할 수 있다.

4. MockMvc vs RestAssured

MockMvc

  • @SpringBootTest의 webEnvironment.MOCK과 함께 사용가능하다.
  • mocking 된 web Environment(ex tomcat) 환경에서 테스트 한다.
    -> 즉, 가짜 웹 환경에서 테스트를 한다.

RestAssured

  • 실제 web environment(Apach Tomcat)을 사용하여 테스트 한다.

5. 테스트 격리

위에서 적었듯이 @webEnvironment에서 RANDOM_PORT를 사용하는 경우(RestAssured를 사용하는 경우) @Transactional을 사용할 수 없다. 따라서 테스트코드간에 서로 영향을 주지 않기 위해서 조치가 필요하다.

@DirtiesContext

  • 효과적인 테스트 수행을 위해 스프링에서는 context caching 기능 지원
  • @DirtiesContext를 활용하여 캐시 기능을 사용하지 않게 설정
  • 매번 Context를 새로 구성하다보니 시간이 많이 걸린다는 단점이 있다.

DatabaseCleanup

@Service
@ActiveProfiles("test")
public class DatabaseCleanup implements InitializingBean {
    @PersistenceContext
    private EntityManager entityManager;

    private List<String> tableNames;

    @Override
    public void afterPropertiesSet() {
        tableNames = entityManager.getMetamodel().getEntities().stream()
                .filter(e -> e.getJavaType().getAnnotation(Entity.class) != null)
                .map(e -> CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, e.getName()))
                .collect(Collectors.toList());
    }

    @Transactional
    public void execute() {
        entityManager.flush();
        entityManager.createNativeQuery("SET REFERENTIAL_INTEGRITY FALSE").executeUpdate();

        for (String tableName : tableNames) {
            entityManager.createNativeQuery("TRUNCATE TABLE " + tableName).executeUpdate();
            entityManager.createNativeQuery("ALTER TABLE " + tableName 
            			+ "ALTER COLUMN ID RESTART WITH 1").executeUpdate();
        }

        entityManager.createNativeQuery("SET REFERENTIAL_INTEGRITY TRUE").executeUpdate();
    }
  • EntityManager를 활용하여 테이블 이름 조회 후 각 테이블 Truncate 수행
  • ID auto increment 숫자를 1로 복구 시킨다.
  • XXXRepository.deleteAll() 을 사용하면 의존성이 높아지고, Repository가 바뀌면 깨지기 쉬운 테스트 코드가 되기때문에 의존성을 없앤 dataBaseCleanUp을 사용한다.


인수 조건, 인수 테스트 작성 팁

1. 인수 조건을 테스트로 옮기기

Feature 기준으로 인수 테스트 클래스를 나눌 수 있다.
Background 기준으로 setUp 메소드(@beforeEach)를 작성할 수 있다.
Scenario 기준으로 인수 테스트 메소드를 작성할 수 있다.
Feature 내부에 있는 Scenario는 같은 테스트 픽스쳐를 공유한다.

2. Given / When / Then

When -> Then -> Given 순서로 작성하는 것을 추천

given, when, then에서 명확한 것은 When이다. 어떤 API를 콜할 것인지는 명확하기 때문이다.
그리고 그다음으로 명확한 것은 then이다. 내가 어떤 값을 기대하고 있는지는 이미 알고 있기 때문이다.

그런 다음에 given을 하는 것이다. 이런 요청을 했을 때 이런 응답이 오려면 어떤 값을 넣어야 할까 이런 순서로 하니 자연스러웠다.

profile
성장에 대한 경험을 공유하고픈 자발적 경험주의자
post-custom-banner

0개의 댓글