주요글: 도커 시작하기
반응형

이전 글(JUnit 5 소개 http://javacan.tistory.com/463)에 이어 Jupiter API에 대해 좀 더 알아보자. 이 글에서 알아볼 내용은 Assume, @Nested, 태깅에 대한 것이다.


Assumption을 이용한 상황에 따른 테스트 실행


로컬 개발 PC에서만 테스트를 실행하거, 특정 OS에서만 테스트를 실행하고 싶을 때가 있을 것이다. 이럴 때 사용할 수 있는 것이 Assumptions이다. 아래 코드를 보자.


import static org.junit.jupiter.api.Assumptions.assumeTrue;


public class AssumptionTest {

    @Test

    void runTest_IfWindonw() {

        assumeTrue(System.getProperty("os.name").startsWith("Windows"));

        assertEquals(1, 2);

    }


    @Test

    void runTest_IfLinux() {

        assumeTrue(() -> System.getProperty("os.name").startsWith("Linux"));

        assertEquals(1, 2);

    }

}


Assumptions.assumeTrue()는 인자로 전달받은 값이 true이면 이후 테스트를 진행하고, 그렇지 않으면 테스트를 생략한다. assumeTrue()에 전달한 값이 false인 경우 테스트를 생략하는 것이지 해당 테스트가 실패하는 것은 아니다.


두 번째 테스트를 보면 assumeTrue()에 람다식을 전달하고 있다. 이 람다식은 결과를 boolean을 리턴하는데, 이 결과 값에 따라 테스트를 진행하거나 생략한다.


assumeFalse()의 경우는 해당 가정이 false인 경우에만 테스트를 진행한다.


assumeTrue()와 assumeFalse()는 가정이 충족하지 않으면 테스트 메서드 전체를 생략하는데, assumingThat()은 지정한 가정을 충족한 경우 지정한 검증을 수행한다. 다음은 사용 예이다.


    @Test

    void runTest() {

        String osName = System.getProperty("os.name");

        assumingThat(

                osName.startsWith("Linux"), // (1) 가정 boolean 또는 BooleanSupplier

                () -> assertEquals(1, 2) // (2) 가정을 충족할 때 실행할 코드(Executable 타입)

        );

        assertEquals(1, 1); // (3)

    }


assumingThat()의 첫 번째 인자의 값이 true이면, 두 번째 인자로 받은 검증을 수행한다. 위 코드의 경우 OS 이름이 Linux로 시작하는 경우 assertEquals(1, 2) 코드를 실행한다. 위 테스트를 윈도우에서 실행하면 assumingThat()의 (1)이 false이므로, (2)의 검증 코드를 실행하지 않으므로 테스트에 통과한다. 반면에 위 테스트를 리눅스에서 실행하면 (1)이 true이므로 (2)를 실행하고 그 결과 테스트에 실패한다.


@Nested를 이용한 중첩 구성


@Nested를 사용하면 중첩된 구조로 테스트를 구성할 수 있다. 기존에는 JUnit과 다른 도구를 함께 사용해야  중첩 구조를 가진 테스트를 구성할 수 있었는데 이제 Jupiter API 만으로 중첩 구조 테스트를 작성할 수 있다.


@Nested를 사용할 때의 개략적인 구조는 다음과 같다.


@DisplayName("중첩 구조 테스트")

public class AuthenticatorTest {

    private Authenticator authenticator = new Authenticator();

    private MemoryUserRepository mockRepository = new MemoryUserRepository();


    @BeforeEach

    void setUp() {

        authenticator.setUserRepository(mockRepository);

    }


    @Test

    void when_Use_BadParam_Then_IAE_Thrown() {

        assertThrows(IllegalArgumentException.class,

                () -> authenticator.authenticate(null, null));

    }


    @Nested

    public class GivenNoUser {

        @BeforeEach

        void givenNoUser() {

            mockRepository.clear();

        }


        @Test

        void when_Auth_Then_Fail() {

            ...검증코드

        }

    }


    @Nested

    public class GivenUser {

        private String userId = "user";


        @BeforeEach

        void givenUser() {

            mockRepository.save(new User(userId, "pw"));

        }


        @Test

        void when_Use_NoMatchPw_then_Fail() {

            ...검증코드

        }

    }

}


중첩 테스트를 사용하면 상황이나 실행 부분을 별도 클래스로 분리해서 구현할 수 있는데, 이는 테스트 코드 구조를 관리하는데 도움이 된다.



태깅과 필터링


@Tag를 사용하면 테스트 클래스나 메서드에 태그를 달 수 있다.


- 테스트 클래스에 붙인 예


@Tag("slow")

@DisplayName("중첩 구조 테스트")

public class AuthenticatorTest {

    ... 테스트 코드

}


- 테스트 메서드에 붙인 예


@Tag("very-slow")

@Test

void verySlowTest() {

    ...

}


JUnit Platform은 테스트 대상을 고를 때 이 태그를 이용한다. 메이븐을 사용할 경우 다음과 같은 설정을 사용해서 테스트에 포함하거나 제외시킬 태그를 선택할 수 있다.


<plugin>

    <artifactId>maven-surefire-plugin</artifactId>

    <version>2.19.1</version>

    <configuration>

        <properties>

            <includeTags>slow,very-slow</includeTags>

            <excludeTags>pay</excludeTags>

        </properties>

    </configuration>

    <dependencies>

        ...JUnit 5 관련 의존

    </dependencies>

</plugin>


includeTags 프로퍼티는 테스트에 포함시킬 태그 목록을 지정하고 excludeTags는 테스트에서 제외할 태그 목록을 지정한다. 위 경우는 slow와 very-slow 태그가 붙은 테스트 중에서 pay 태그가 붙은 테스트를 제외한 나머지 테스트를 실행한다. includeTags만 있으면 해당 태그가 붙은 테스트만 실행하고, excludeTags만 있으면 해당 태그가 붙은 테스트를 제외한 나머지 테스트를 실행한다.


그레이들을 사용한다면 빌드에 다음 설정을 추가한다.


junitPlatform {

    filters {

        tags {

            include 'slow', 'very-slow'

            exclude 'pay'

        }

    }

}


참고: JUnit 5 연습에 사용한 코드: https://github.com/madvirus/junit5-prac


+ Recent posts