[Test] JUnit5을 이용한 단위 테스트

wlsh44·2022년 9월 27일

테스트

목록 보기
1/3

JUnit5

JUnit5는 JUnit Platform, JUnit Jupiter, JUnit Vintage로 구성되어 있습니다.

JUnit Platform은 JUnit의 뼈대라고 할 수 있는 TestEngine API를 가지고 있으며 실제 테스트를 찾아 실행시키는 역할을 합니다.

또한 JUnit Platform을 통해 여러 유명한 IDE들(IntelliJ, Eclipse, Visual Studio Code 등)의 지원을 받아 더욱 편리하게 테스트를 할 수 있습니다.

JUnit JupiterTestEngine을 구현화하여 실제 개발자들이 테스트를 할 수 있는 `programming model`이 들어있습니다.

위의 사진처럼 가장 많이 사용하는 @Test, @DisplayName 등이 JUnit Jupiter에서 구현이 되어있습니다.

또한 다른 프레임워크를 이용해 테스트할 수 있는 `extension model`이 있습니다. 바로 많은 사람들이 알고 있는 @ExtendWith가 여기에 있습니다.

JUnit Vintage는 JUnit3, 4에서도 TestEngine이 돌아가게 하는 모듈입니다. 하지만 JUnit 4.12 이후의 버전이 class path 또는 module path에 있어야 한다고 합니다.

Gradle 추가

우선 gradle의 버전이 4.6 이상이어야 하므로 확인을 해줍니다.

./gradlew -v

이전 버전들과는 달리 platform을 지정을 해줘야 합니다.

test {
    useJUnitPlatform()
}

그리고 다음처럼 두 개의 dependency를 지정해 줍니다.

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
}

이 글 작성 기준으로 가장 최신 버전인 5.8.2를 불러왔습니다.

최신 버전은 여기서 확인해주세요.

JUnit 테스트

@Test

제일 중요한 annotation인 테스트 메서드임을 알려주는 @Test입니다.

package calculator;

public class Calculator {
    public int plus(int a, int b) {
        return a + b;
    }

    public int divide(int a, int b) {
        return a / b;
    }
}

위와 같은 계산기가 있다고 했을 때 테스트 코드를 작성해보겠습니다.

src/test/java/calculator 위치에 CalculatorTest라는 테스트 클래스를 만듭니다. (만약 IntelliJ를 쓰신다면 command(⌘) + shift(⇧) + T 를 누르면 같은 패키지의 위치에 테스트 클래스가 생성이 됩니다.)

package calculator;

import org.junit.jupiter.api.Test;

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

class CalculatorTest {

    Calculator calculator = new Calculator();

    @Test
    void test() {
        int result = calculator.plus(1, 2);

        assertEquals(3, result);
    }

}

이후 IntelliJ 기준으로 다음과 같이 테스트 코드를 실행할 수 있습니다.

테스트를 성공하면 아래처럼 초록불과 함께 테스트를 통과했다는 결과를 볼 수 있습니다.

테스트에 실패하면 x표시와 함께 왜 실패했는지에 대한 정보가 나옵니다.

Assertions

앞선 테스트 코드에서 assertEqauls이라는 메서드를 통해 테스트를 검증했습니다.

이와 같은 메서드들이 바로 JUnit Jupiter에서 제공하는 Assertion mothods입니다.

그렇다면 어떤 메서드들이 있는지 알아보겠습니다.

assertEqauls, assertNotEquals

아까 확인했던 assertEquals와 이와 유사한 assertNotEquals입니다.

들어온 두 값을 비교하여 같은지, 다른지에 따라 테스트의 성공 여부를 판단합니다.

    @Test
    @DisplayName("assertEquals, assertNotEquals 테스트")
    void assertEqualsTest() {
        int result = calculator.plus(1, 2);

        assertEquals(3, result);
        assertNotEquals(4, result);
    }

assertTrue, assertFalse

boolean 값을 받아 true인지 false인지 테스트합니다.

    @Test
    @DisplayName("assertTrue, assertFalse 테스트")
    void assertTrueTest() {
        boolean given = true;

        assertTrue(given);
        assertFalse(!given);
    }

assertArrayEquals

array의 안에 있는 값을 비교하여 테스트합니다.

    @Test
    @DisplayName("assertArrayEquals 테스트")
    void arrayEqualsTest() {
        int[] given = new int[]{1, 2, 3};
        int[] expected = new int[]{1, 2, 3};

        assertArrayEquals(expected, given);
    }

assertNull, assertNotNull

객체가 null인지 아닌지 테스트합니다.

    @Test
    @DisplayName("assertNull, assertNotNull 테스트")
    void assertNullTest() {
        Object nullObj = null;
        Object obj = new Object();

        assertNull(nullObj);
        assertNotNull(obj);
    }

assertThrows

올바른 exception을 발생시키는지 테스트하는 메서드입니다.

    @Test
    @DisplayName("assertThrows 테스트")
    void assertThrowsTest() {
        assertThrows(ArithmeticException.class, () -> calculator.divide(1, 0));
    }

그 외 assertions들

위에서 소개해드린 Assertions 말고도 assertTimeout, assertAll 등이 있습니다.

자세한 건 docs를 확인해주세요.

LifeCycle 어노테이션

@beforeEach

각각의 테스트 메서드 전에 실행됩니다.

@AfterEach

각각의 테스트 메서드가 실행 된 후 실행됩니다.

@BeforeAll

모든 테스트 메서드 전에 실행됩니다.

@AfterAll

모든 메서드 이후에 실행됩니다.

import org.junit.jupiter.api.*;

public class LifeCycleTest {

    @BeforeAll
    static void beforeAll() {
        System.out.println("beforeAll!\n");
    }

    @BeforeEach
    void beforeEach() {
        System.out.println("beforeEach!");
    }

    @AfterEach
    void afterEach() {
        System.out.println("afterEach!\n");
    }

    @AfterAll
    static void afterAll() {
        System.out.println("afterAll!");
    }

    @Test
    void test1() {
        System.out.println("test1 실행");
    }

    @Test
    void test2() {
        System.out.println("test2 실행");
    }

    @Test
    void test3() {
        System.out.println("test3 실행");
    }
}

@DisplayName

테스트 클래스 또는 테스트 케이스에 이름을 지정해줄 수 있습니다.

@DisplayName을 이용하면 테스트 메서드의 이름을 한글로 작성하지 않아도 되고 띄어쓰기를 사용할 수 있는 장점이 있습니다.

그리고 IDE에서 테스트를 진행했을 때 해당 이름에 맞게 표시를 해줍니다.

만약 IntelliJ와 gradle을 사용하시는 경우에 테스트를 실행을 했는데 위처럼 표시가 안되고 테스트가 끝난다면 command(⌘) + , -> gradle에 들어가 다음처럼 바꿔준 후에 다시 빌드하여 테스트를 하시면 됩니다.

@Disabled

개발을 하다 보면 버그가 발생하거나 테스트를 진행하고 싶지 않은 경우가 있습니다.

이런 경우에는 테스트 전체를 주석처리하는 방법도 있지만 나중에 까먹게 되거나 github에 올릴 때 주석처리된 코드를 올리는 상황이 발생합니다.

그럴 때 사용하는 annotation이 @Disabled입니다. 이를 통해 어떤 이유에서 테스트가 disabled 되었는지 명시할 수 있는 이점이 있습니다.

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

class DisabledTest {

    @Test
    @Disabled("Disabled until bug #99 has been fixed")
    void testWillBeSkipped() {
    }

}

disabled 처리를 한 후 테스트 코드를 실행시키면 위처럼 실행되지 않으며 명시해준 이유가 표시됩니다.

@Nested

하나의 테스트 코드 안에서 분류를 할 때 사용되는 @Nested 입니다.

다음과 같이 클래스로 분류를 하고 @Nested를 붙여주는 식으로 사용합니다.

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

@DisplayName("그룹 테스트")
public class NestedTest {

    @Nested
    @DisplayName("그룹 A 테스트")
    class ATest {

        @Test
        @DisplayName("A - 1 테스트")
        void test1() {
        }

        @Test
        @DisplayName("A - 2 테스트")
        void test2() {
        }
    }

    @Nested
    @DisplayName("그룹 B 테스트")
    class BTest {

        @Test
        @DisplayName("B - 1 테스트")
        void test1() {
        }

        @Test
        @DisplayName("B - 2 테스트")
        void test2() {
        }
    }
}

업로드중..

테스트의 결과를 좀 더 깔끔하게 볼 수 있어서 좋은 장점이 있지만 너무 많이 사용하게 되면 테스트 코드 자체에 대한 가독성이 떨어져 적절하게 사용하는 점을 유의해야 합니다.

그 외

위에서 소개해드린 기능들 말고도 하나의 테스트 안에서 여러 테스트 케이스를 돌릴 수 있게 하는 `@ParameterizedTest`, 테스트의 순서를 정해주는 `@Order` 등 많은 기능들을 제공합니다. 이 기능들에 대해서는 추후에 포스팅해보도록 하겠습니다.

참고자료

https://www.baeldung.com/junit-5-gradle

profile
정리정리

0개의 댓글