테스트코드/개요

2. 단위 테스트란 무엇인가

feel2 2024. 3. 25. 19:49
반응형

통합 테스트

런던파의 통합 테스트 : 실제 협력자 객체를 사용하는 모든 테스트를 통합 테스트이다. 고전파는 런던파 입장에서 모두 통합 테스트이다.

고전파의 통합 테스트 : 공유 의존성 접근하는 테스트 또는 둘 이상의 동작 단위 검증할 때 통합 테스트이다.

 

단위 테스트의 정의

- 작은 코드 조각을 검증
- 빠르게 수행 가능
- 격리된 방식으로 처리 가능

→ 하나의 모듈을 기준으로 독립적으로 진행되는 가장 작은 단위의 테스트

 

 

좋은 테스트의 규칙(FIRST)

  1. Fast: 테스트는 빠르게 동작하여 자주 돌릴 수 있어야 한다.
  2. Independent: 각각의 테스트는 독립적이며 서로 의존해서는 안된다.
  3. Repeatable: 어느 환경에서도 반복 가능해야 한다.
  4. Self-Validating: 테스트는 성공 또는 실패로 bool 값으로 결과를 내어 자체적으로 검증되어야 한다.
  5. Timely: 테스트는 적시에 즉, 테스트하려는 실제 코드를 구현하기 직전에 구현해야 한다.

 

 

테스트를 바라보는 관점(고전파 VS 런던파)

격리 수준을 어떻게 하느냐에 따라 크게 2가지 관점으로 나뉨

  • 고전파
    • 고전주의적 접근법
    • 테스트 주도 개발(켄트 백, 테스트 주도 개발)
    • 의존성과 테스트 대상 시스템 모두 준비해야 함
  • 런던파
    • 목 추종자
    • 런던 스타일
    • 테스트 대상 시스템(SUT, System Under Test)을 협력자(Collaborator)에게서 격리
    • 클래스 간의 의존성을 줄일 수 있음
    • SUT 에 보다 집중 가능

 

 

런던파의 경우, 테스트 대상 시스템의 의존성을 테스트 대역으로 대체 → 테스트 대상 시스템만 검증하는데 집중 가능

 

고전파의 예

 

@SpringBootTest
@Transactional
class OrderServiceTest {

    @Autowired
    EntityManager em;
    @Autowired
    OrderService orderService;

    @Autowired
    OrderRepository orderRepository;

    @Test
    public void 상품주문(){
        //given
        Member member = createMember();

        Book book = createBook("시골 JPA", 10000, 10);

        //when
        int orderCount = 2;
        Long orderId = orderService.order(member.getId(), book.getId(), orderCount);

        //then
        Order getOrder = orderRepository.findOne(orderId);

        // 상품 주문시 상태는 ORDER
        assertThat(getOrder.getStatus()).isEqualTo(OrderStatus.ORDER);
        // 주문한 상품 종류 수는 정확해야 한다.
        assertThat(getOrder.getOrderItems().size()).isEqualTo(1);
        // 주문 가격은 가격 * 수량이다.
        assertThat(getOrder.getTotalPrice()).isEqualTo(10000*orderCount);
        // 주문 수량만큼 재고가 줄어야 한다.
        assertThat(book.getStockQuantity()).isEqualTo(8);

    }

여기서 SUT는 상품 주문(order)이고, 협력자는 book 과 member 이다. 대표적인 고전파 방법으로 테스트를 한 예이다.

 

런던파의 예

 

MemberService의 경우 구현체는 없고, 인터페이스만 존재한다.

@DataJpaTest
@ExtendWith(MockitoExtension.class)
@Slf4j
class StudyServiceTest {

    @Mock MemberService memberService;  // 선언적으로 Mock 만드는 방법

    @Mock StudyRepository studyRepository;

    @Test
    void createNewStudy() {

        // Given
        StudyService studyService = new StudyService(memberService, studyRepository);
        assertNotNull(studyService);

        // stub 세팅
        Member member = new Member();
        member.setId(1L);
        member.setEmail("asdf@email.com");

        Study study = new Study(10, "테스트");

        given(memberService.findById(1L)).willReturn(Optional.of(member));
        given(studyRepository.save(study)).willReturn(study);

        // When
        studyService.createNewStudy(1L, study);

        // Then
        assertNotNull(study.getOwnerId());
        assertEquals(member.getId(), study.getOwnerId());

        then(memberService).should(times(1)).notify(study);
        then(memberService).shouldHaveNoInteractions();
    }

}

Mockito 라이브러리를 사용하여 런던파 스타일로 테스트를 구현한 것

 

 

격리 주체 단위 크기 테스트 대역 사용 대상

  격리 주체 단위 크기 테스트 대역 사용 대상
런던파 단위 단일 클래스 불변 의존성 외의 모든 의존성
고전파 단위 테스트 단일 클래스 또는 클래스 세트 공유 의존성

 

통합 테스트

  • 런던파의 통합 테스트 : 실제 협력자 객체를 사용하는 모든 테스트를 통합 테스트이다. 고전파는 런던파 입장에서 모두 통합 테스트이다.
  • 고전파의 통합 테스트 : 공유 의존성 접근하는 테스트 또는 둘 이상의 동작 단위 검증할 때 통합 테스트이다.

 

엔드 투 엔드 테스트(end-to-end test)

엔드 투 엔드 테스트는 공유 의존성뿐만 아니라 조직 내 다른 팀이 개발한 코드 등과 통합해 작동하는 테스트다. 일반 통합 테스트보다 더 많은 의존성이 있다. UI(User Interface), GUI(Graphic User Interface) 테스트라고도 할 수 있다.

엔드 투 엔드 테스트 작성에 가장 많은 비용이 발생하기 때문에 모든 단위 테스트, 통합 테스트 통과한 후 후반에 작성, 실행하는 것이 좋다.

 

참조

  • 단위테스트(블라디미르 크리코프)
반응형

'테스트코드 > 개요' 카테고리의 다른 글

6. 단위 테스트 스타일  (0) 2024.03.25
5. 목과 테스트의 취약성  (0) 2024.03.25
4. 좋은 단위 테스트의 4대 요소  (2) 2024.03.25
3. 단위 테스트 구조  (0) 2024.03.25
1. 단위 테스트의 목표  (1) 2024.03.25