DEV/JUnit

[JUnit] JUnit 핵심 (1) 생애주기와 동작원리 / 테스트 클래스와 메서드 / 애노테이션

Imvory 2024. 6. 20. 15:26

TDD 하고싶어서 학습하는 JUnit 프레임워크, 책을 기반으로 학습하고 정리하고자한다.

 

참고 도서

https://www.yes24.com/Product/Goods/126579542

 

JUnit IN ACTION 3판 - 예스24

자바 단위 테스트를 위해 알아야 할 모든 것JUnit은 자바 애플리케이션을 단위 테스트하기 위한 사실상의 표준이다. 자바 개발자에게 JUnit은 이제 필수가 되었다. 특히 JUnit 5에서는 모던 자바(자

www.yes24.com

 

해당 책에서는 JUnit5를 주로 다루고 JUnit4와 비교하는 부분이 있을 것으로 보인다.

 

샘플 코드

https://github.com/devkunst/junit-in-action-third-edition-kr

 

GitHub - devkunst/junit-in-action-third-edition-kr: JUnit in Action Third Edition

JUnit in Action Third Edition. Contribute to devkunst/junit-in-action-third-edition-kr development by creating an account on GitHub.

github.com

 


 

 

- 테스트 클래스 : 클래스, 정적 멤버 클래스, 하나 이상의 테스트 메서드를 포함하는 @Nested 애노테이션이 붙은 내부 클래스를 말한다.

  • 추상 클래스일 수 없으며 단일 생성자를 가져야한다.
  • 테스트 클래스의 생성자는 파라미터가 아예 없거나, 런타임 의존성 주입으로 동적으로 리졸브할 수 있는 파라미터만 사용할 수 있다.
  • JUnit4와 다르게 JUnit5부터 public이 아닌 default 접근 제어자를 사용할 수 있다.

 

- 테스트 메서드 : @Test, @RepeatedTest, @ParameterizedTest, @TestFactory, @TestTemplate 애노테이션이 붙은 메서드를 말한다.

  • 추상 메서드일 수 없으며 반환 값을 가질 수 없다. 무조건 void 타입.

 

- 생애주기 메서드 : @BeforeAll, @AfterAll, @BeforeEach, @AfterEach 애노테이션이 붙은 메서드를 말한다.

  • @BeforeAll : 전체 테스트가 실행되기 전에 한 번 실행. 테스트 클래스에 @TestInstance(Lifecycle.PER_CLASS) 애노테이션이 없으면 static으로 선언해야한다.
  • @BeforeEach : 각 테스트가 실행되기 전에 실행된다.
  • @AfterAll :전체 테스트가 실행 된 후 한 번 실행. @TestInstance(Lifecycle.PER_CLASS) 애노테이션이 없으면 static으로 선언해야한다.
  • @AfterEach : 각 테스트가 실행된 이후에 실행된다.

 

JUnit은 테스트 메서드의 격리성을 보장하고 테스트 코드에서 의도치 않은 부수효과(side effect)를 방지하기 위해

@Test 메서드를 호출하기 전에 테스트 클래스 인스턴스를 매번 새로 만든다.

 

테스트 메서드는 매번 새로 만들어진 테스트 클래스 인스턴스에서 실행되므로 테스트 메서드 간에 인스턴스 변수를 재사용할 수 없다.

 

대신 @TestInstance(Lifecycle.PER_CLASS) 애노테이션을 추가하면 JUnit5는 동일한 테스트 인스턴스를 가지고 클래스에 있는 모든 테스트 메서드를 실행한다. 테스트 클래스 인스턴스가 메서드 단위가 아닌 클래스 단위로 생성되는 것이다.

 

 

@DisplayName

package com.study.junit.ch02;

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@DisplayName("Test class showing the @DisplayName annotation.")
public class DisplayNameTest {

    private SUT systemUnderTest = new SUT();

    @Test
    @DisplayName("Our system under test says hello.")
    void testHello() {
        assertEquals("Hello", systemUnderTest.hello());
    }

    @Test
    @DisplayName("😱")
    void testTalking() {
        assertEquals("How are you?", systemUnderTest.talk());
    }

    @Test
    void testBye() {
        assertEquals("Bye", systemUnderTest.bye());
    }

}
  • 테스트 클래스, 테스트 메서드에 사용
  • 테스트 목적을 알려줄 수 있는 완전한 문장으로 적는 것이 일반적이다.
  • 공백, 특수문자, 이모지도 사용할 수 있다.
  • 디스플레이 네임을 따로 명시하지 않은 테스트는 메서드 이름을 표시한다.

실행결과

DisplayNameTest 실행결과

책에서와는 다르게 나는 인코딩 설정을 안해줘서 그런지 물음표로 나온다 ..

이모지 쓸 일은 없을 것 같으니 패스 ..

 

 

@Disabled

package com.study.junit.ch02;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class DisabledMethodTest {
    private SUT systemUnderTest = new SUT("테스트 대상 시스템");

    @Test
    @Disabled //테스트 비활성화 이유 알 수 없음
    void testRegularWork() {
        boolean canReceiveRegularWork =
                systemUnderTest.canReceiveRegularWork();
        assertTrue(canReceiveRegularWork);
    }

    @Test
    @Disabled("기능 개발 중")
    void testAdditionalWork() {
        boolean canReceiveAdditionalWork =
                systemUnderTest.canReceiveAdditionalWork();
        assertFalse(canReceiveAdditionalWork);
    }
}
  • 테스트 클래스나 테스트 메서드에서 사용
  • 해당 애노테이션을 붙이면 클래스단위나 메서드 단위로 비활성화 되어 테스트가 실행되지 않는다.
  • 비활성화한 이유를 구체적으로 작성할 것을 권장한다.