테스트/0+ JUnit

[JUnit5] Assertions 기본 사용법

힘들면힘을내는쿼카 2023. 5. 5. 14:06
728x90
반응형

[JUnit5] Assertions 기본 사용법

 

Jupiter에서 제공하는 Assertions에 대해서 알아보자.

자주 사용하는 Assertions

  • assertEqulas(expected, actual)
    • 실제 값이 기대한 값과 같은지 확인

 

  • assertNotNull(actual)
    • actualnull이 아닌지

 

  • assertTrue(boolean)
    • 조건이 참(true)인지 확인

 

  • assertAll(executables…)
    • 모든 확인 구문 확인

 

  • assertThrows(expectedType, executable)
    • 예외 발생 확인

 

  • assertTimeout(duration, executable)
    • 특정 시간 안에 로직이 완료되는지 확인
    • 로직이 완료될 때 까지 기다림

 

  • assertTimeoutPreemptively(expectedType, executable)
    • 특정 시간 안에 로직이 완료되는지 확인
    • 특정 시간 안에 로직이 완료 안되면 바로 테스트 종료
    • 별도의 스레드에서 테스트를 수행
      • ThreadLocal을 사용하는 로직인 경우 주의
      • 스프링에서 JPA를 이용하여 쿼리를 수행할 때 롤백이 안될 수도 있음
        • 스프링 트랜잭션 처리는 기본적으로 ThreadLocal 전략

실습

아래와 같은 클래스를 테스트한다고 가정해봅시다!

 

CalmDownMan

@Data
public class CalmDownMan {
    private String name;
    private int age;
    private CalmDownManStatus status;

    public CalmDownMan(int age) {
        if(age < 0) {
            throw new IllegalArgumentException("나이는 0보다 커야합니다.");
        }
        this.age = age;
        this.status = CalmDownManStatus.OFF_AIR;
    }
}

 

assertEqulas

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

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

class CalmDownManTest {

      @Test
    @DisplayName("assertEquals 테스트")
    void assertEqualsTest() {
        CalmDownMan calmDownMan = new CalmDownMan(40);
        // 람다로 작성하면 지연연산을 하기 때문에
        // 테스트가 실패 했을때만 문구를 표시한다.
        // 성능에 도움이 된다.
        assertEquals(calmDownMan.getAge(), 40, () -> "침착맨의 나이는 "+calmDownMan.getAge()+"살 입니다.");
        assertEquals(calmDownMan.getStatus(), CalmDownManStatus.OFF_AIR, () -> "침착맨을 생성하면 기본 상태는 "+CalmDownManStatus.OFF_AIR+" 입니다.");
    }
}

 

message에 해당하는 부분을 람다로 작성하면,
람다는 지연 연산을 하기 때문에 테스트가 실패 했을 경우에만 String 연산을 수행하게 됩니다.

 

assertNotNull

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

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

class CalmDownManTest {

      @Test
    @DisplayName("assertNotNull 테스트")
    void assertNotNullTest() {
        CalmDownMan calmDownMan = new CalmDownMan(40);
        assertNotNull(calmDownMan, () -> "침착맨을 생성하면 null이 아닙니다.");
    }
}

 

assertTrue

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

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

class CalmDownManTest {

    @Test
    @DisplayName("assertTrue 테스트")
    void assertTrueTest() {
        CalmDownMan calmDownMan = new CalmDownMan(40);
        assertTrue(calmDownMan.getAge() == 40, () -> "침착맨의 나이는 "+calmDownMan.getAge() +" 입니다.");
    }
}

 

assertAll

assertAll을 사용하면 모든 테스트 구문을 확인할 수 있습니다.
중간에 테스트가 실패해도 모든 테스트 구문이 실행 됩니다.

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

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

class CalmDownManTest {

    @Test
    @DisplayName("assertAll 테스트")
    void assertAllTest() {
        CalmDownMan calmDownMan = new CalmDownMan(40);
        assertAll(
                () -> assertEquals(calmDownMan.getAge(), 20, () -> "침착맨의 나이는 "+calmDownMan.getAge()+"살 입니다."),
                () -> assertEquals(calmDownMan.getStatus(), CalmDownManStatus.OFF_AIR, () -> "침착맨을 생성하면 기본 상태는 "+CalmDownManStatus.OFF_AIR+" 입니다."),
                () -> assertNotNull(calmDownMan, () -> "침착맨을 생성하면 null이 아닙니다."),
                () -> assertTrue(calmDownMan.getAge() > 40, () -> "침착맨의 나이는 "+calmDownMan.getAge() +" 입니다.")
        );
    }
}

 

1번 테스트 실패해도
그다음 테스트를 실행하여 3번 테스트도 실패한 것을 알 수 있습니다.

 

assertThrows

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

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

class CalmDownManTest {

    @Test
    @DisplayName("assertThrows 테스트")
    void assertThrowsTest() {
        IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> new CalmDownMan(-10));
        String message = e.getMessage();
        assertEquals("나이는 0보다 커야합니다.", message);
    }
}

 

assertTimeout

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

import java.time.Duration;

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

class CalmDownManTest {

    @Test
    @DisplayName("assertTimeout 테스트")
    void assertTimeoutTest() {
        assertTimeout(Duration.ofMillis(100), () -> {
            CalmDownMan calmDownMan = new CalmDownMan(10);
            Thread.sleep(1000);
        });
    }
}

 

Duration에서 설정한 100ms를 초과하면 테스트에 실패합니다.
테스트를 이미 실패했지만, 해당 로직이 완료될 때까지 테스트를 수행합니다.
테스트를 수행하는데 1초 33ms가 걸린것을 확인할 수 있습니다.

 

assertTimeoutPreemptively

assertTimeoutPreemptively는 별도의 스레드에서 코드블록을 실행하기 때문에
ThreadLocal을 사용하는 로직을 수행할 시 주의해야 합니다.

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

import java.time.Duration;

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

class CalmDownManTest {

    @Test
    @DisplayName("assertTimeout 테스트")
    void assertTimeoutPreemptivelyTest() {
        /**
         * 특정 시간안에 실행이 안되면 바로 테스트 종료
         * 별도의 스레드에서 코드블록을 실행함
         * ThreadLocal을 사용하는 로직은 주의해야 합니다.
         *
         * 예를 들어 스프링 트랜잭션 처리는 기본적으로 ThreadLocal 전략을 사용합니다.
         * (ThreadLocal은 다른 스레드간 메모리 공유가 불가합니다.)
         * assertTimeoutPreemptively()는 별도의 스레드에서 코드블록을 실행하기 때문에
         * 스프링의 트랜잭션 설정을 가지고 있는 스레드(ThreadLocal을 사용)를 실행할 수 없습니다.
         *
         * 따라서 롤백이 안되고 DB에 그대로 반영될 수도 있습니다.^^
         */
        assertTimeoutPreemptively(Duration.ofMillis(100), () -> {
            CalmDownMan calmDownMan = new CalmDownMan(40);
            Thread.sleep(1000);
        });
    }
}

 

Duration에서 설정한 100ms를 초과하면 테스트에 실패합니다.
테스트를 실패하는 즉시 테스트를 종료 합니다.
테스트를 수행하는데 116ms가 걸린것을 확인할 수 있습니다.

참고

728x90
반응형