Projects/Java [Personal]

Test - 2부

montmer27 2026. 2. 12. 10:05

단위 테스트 하는 법

 

목적: 전부를 테스트하는 것이 아닌, 핵심 로직만 테스트한다.

 

예) 내가 직접 구현한 코드만 테스트, 단순 CRUD는 단위 테스트에서 굳이 테스트 X 

 

방법:

1) 원본 코드 리팩터링: 핵심 로직만 별도의 클래스 파일의 static 메서드로 분리한다. 원본 코드에는 static 메서드만 남긴다. 

 

2) static 메서드로 test 파일을 만든다. 테스트 대상은 아니지만 테스트가 돌아가기 위해 어쩔 수 없이 필요한 외부 의존성은 Mock으로 주입받는다.

2-1) Mock으로 주입받을 수 없는 외부 의존성이 포함되어 있을 경우, 단위 테스트 대신 통합 테스트를 시행한다.

 

3. 테스트 파일을 만들 때 참고

  • @BeforeEach + 메서드: 한 테스트 파일엔 여러 테스트가 있을 수 있다. (성공하는 경우, 예외를 만드는 경우). 모든 테스트를 하기 전에 공통적으로 실행해야 하는 메서드에 이 어노테이션을 붙인다.

 

// example
   Product product;    // 1

    @BeforeEach     
    void initProduct() {      // 2
    	//순서대로 id, name, description, price, amount, saleCount
        product = new Product(1L, "티셔츠", "무지 티 입니다.", 10000L, 100L, 0L);
    }

 

  • @Test + 메서드: 전술했다시피 하나의 테스트 파일은 여러 경우로 이루어진다. 그리고 각각의 테스트는 이 어노테이션이 있어야 한다. IDE는 전체 테스트를 @Test 단위로 구분하여 실시한다. 그래서 모든 @Test가 통과하면 테스트 파일에서 테스트하고자 하는 단위 메서드는 테스트가 끝난 것이다. 

 

  • given-when-then 패턴: 전제-조건-결론의 3단 논법을 테스트에 적용시킨 것이라 생각하면 된다. 방법론이므로 반드시 따를 필요는 없다. given이 빠질 때도 많다. 절대적인 문법은 아니다. 하지만 어떤 조건일 때 어떠해야 한다라는 틀은 테스트에 필수적이다. 
// given이 따로 명시되어 있지 않다.
@Test
    public void 성공_상품_구매() {
        // when
        product.purchased(10L);

        // then
        assertThat(product.getAmount()).isEqualTo(90L);
        assertThat(product.getSaleCount()).isEqualTo(10L);
    }

 

  • asserThat, asserThrows: 우리가 테스트를 통해 의도한 결과 또는 예외를 명시할 때 필요하다. 아래 두 의존성이 필요하다(Test라고 해서 의존성이 필요하지 않은 게 아님!). assertThat/assertThrow 안에 들어간 결과와 테스트 결과가 일치하면 성공, 일치하지 않으면 실패다. 
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;

 

@Test
    public void 실패_상품_재고를_초과하는_구매() {    // 3
        // when
        RuntimeException e = assertThrows(RuntimeException.class,
        	// amount가 100L인데 200L을 주문 -> 재고를 200L만큼 차감하려 시도
            () -> product.purchased(200L));

        // then
        assertThat(e.getMessage()).isEqualTo("티셔츠의 상품 재고가 부족합니다.");
    }