통합 테스트

이유진·2024년 9월 9일
0
post-thumbnail

🌱 통합 테스트

통합테스트란 무엇일까?

  • 단위테스트

    • 하나의 모듈이나 클래스에 대해 세밀한 부분까지 테스트가 가능하다.
    • 하지만, 모듈간의 상호작용 검증은 할 수 없다.
    • 단위 테스트 시 Spring은 동작되지 않는다.
  • 통합 테스트

    • 두 개 이상의 모듈이 연결된 상태를 테스트 할 수 있다.

    • 모듈 간의 연결에서 발생하는 에러 검증이 가능하다.

    • 단, 설정과 모든 빈들을 스캔하여 등록하기 때문에 동작 시간이 오래 걸리고 무겁다.


@SpringBootTest

  • @SpringBootTest : 스프링이 동작되도록 해주는 어노테이션

  • 프로젝트 내부에 있는 모든 스프링 빈들을 스캔하여 등록하고, 애플리케이션 컨텍스트를 생성하여 테스트를 실행한다.

  • 테스트 수행 시 스프링이 동작한다.

    • Spring IoC/DI 기능 사용 가능하다.

    • Repository를 사용해 DB CRUD가 가능하다.


@ 어노테이션

  • @Transactional

    • 클래스 내부의 각각의 테스트 메서드가 실행 될 때마다, 데이터베이스를 rollback한다. 반복 가능한 테스트 코드를 위해 필요하다.
    • 만약, 테스트 후 데이터를 직접 보고 싶다면 @Rollback(false) 어노테이션을 추가하면 된다.
  • @DisplayName

    • 테스트 클래스와 메서드에 이름을 지정해줄 수 있다.
    • 테스트 실행 시 콘솔이나 리포트에 표시되어, 어떤 테스트가 실행되는지 쉽게 알 수 있다.
    @Test
    @DisplayName("테스트의 내용을 한눈에 알아볼 수 있게 네이밍 해줄 수 있습니다.")
    void test1() {
        System.out.println("테스트의 수행 내용들을 빠르게 파악할 수 있습니다.");
    }
  • @TestMethodOrder(MethodOrderer.OrderAnnotation.class)

    • 테스트를 메서드 단위로 순서를 매길 때 사용한다.
    • 원하는 순서에 맞게 메서드에 @Order(2) 에너테이션을 추가하고 괄호안에 순서를 입력한다.
    @Nested
    @DisplayName("주제 별로 테스트를 그룹지어서 파악하기 좋습니다.")
    @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
    class Test1 {
    
        @Order(1)
        @Test
        @DisplayName("Test1 클래스")
        void test() {
            System.out.println("\nTest1 클래스");
        }
    
        @Order(3)
        @Test
        @DisplayName("Test1 - test1()")
        void test1() {
            System.out.println("Test1.test1");
        }
    
        @Order(2)
        @Test
        @DisplayName("Test1 - test2()")
        void test2() {
            System.out.println("Test1.test2");
        }
    }

Given - When - Then 패턴

  • Test Code 스타일을 표현하는 방식을 뜻한다.

  • Given(사전 조건)

    • 테스트 하고자하는 대상을 실제로 실행하기 전에 테스트에 필요한 값(상태)를 미리 선언해둔다.
    • 예) 데이터베이스에 특정 데이터를 삽입하거나, 테스트에 필요한 객체를 초기화한다.
  • When(행동)

    • 테스트 하고자하는 대상을 실제로 실행 시킨다.
    • 예) 메서드를 호출하거나, 특정 이벤트를 발생시킨다.
  • Then(검증)

    • 어떤 특정한 행동(테스트 대상 실행) 때문에 발생할거라고 예상되는 결과에 대해 예측하고 맞는지 확인한다.
    • 예) 결과가 예상한 값과 일치하는지, 예외가 발생하지 않는지 등을 확인한다.

통합 테스트 예시

import com.sparta.myselectshop.dto.ProductMypriceRequestDto;
import com.sparta.myselectshop.dto.ProductRequestDto;
import com.sparta.myselectshop.dto.ProductResponseDto;
import com.sparta.myselectshop.entity.User;
import com.sparta.myselectshop.entity.UserRoleEnum;
import com.sparta.myselectshop.repository.UserRepository;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

// 서버의 PORT 를 랜덤으로 설정합니다.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 
// 테스트 인스턴스의 생성 단위를 클래스로 변경합니다.
@TestInstance(TestInstance.Lifecycle.PER_CLASS) 
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@Transactional
class ProductServiceIntegrationTest {

    @Autowired
    ProductService productService;
    @Autowired
    UserRepository userRepository;

    User user;
    ProductResponseDto createdProduct = null;
    int updatedMyPrice = -1;

    @Test
    @Order(1)
    @DisplayName("신규 관심상품 등록")
    void test1() {

        user = new User("yujin", "yj1234567!", "yj1234@naver.com", UserRoleEnum.USER);
        userRepository.save(user);

        // given
        String title = "Apple <b>에어팟</b> 2세대 유선충전 모델 (MV7N2KH/A)";
        String imageUrl = "https://shopping-phinf.pstatic.net/main_1862208/18622086330.20200831140839.jpg";
        String linkUrl = "https://search.shopping.naver.com/gate.nhn?id=18622086330";
        int lPrice = 173900;

        ProductRequestDto requestDto = new ProductRequestDto(
                title,
                imageUrl,
                linkUrl,
                lPrice
        );
        User user1 = userRepository.findById(1L).orElse(null);

        // when
        ProductResponseDto product = productService.createProduct(requestDto, user1);

        // then
        assertNotNull(product.getId());
        assertEquals(title, product.getTitle());
        assertEquals(imageUrl, product.getImage());
        assertEquals(linkUrl, product.getLink());
        assertEquals(lPrice, product.getLprice());
        assertEquals(0, product.getMyprice());
        createdProduct = product;
    }

위의 테스트 코드는 회원이 신규 상품을 등록하기 위한 테스트 코드 예시 이다.

Given절에서는 관심상품을 등록하기 위한 요청 데이터를 설정한다. Dto 객체를 생성하고, 기존의 user 정보를 user1로 가져온다.

when절에서는 productService.createProduct() 메서드를 호출하여 상품을 생성한다. 이 때, 설정한 Dto와 user1을 인자로 전달한다.

Then절에서는 생성된 상품 아이디가 null이 아닌지 확인하고, 요청 데이터와 실제 응답 데이터가 일치하는지 검증한다.


참고 URL

https://caffeineoverflow.tistory.com/144

https://curiousjinan.tistory.com/entry/integration-vs-unit-testing

profile
🙌중요한건 꺾였는데도 그냥 하는 마음

0개의 댓글