Assertions

최준호·2022년 6월 28일
0

JUnit5

목록 보기
2/4
post-thumbnail

✍ Assertions이란?

Assertion이란 JUnit5에서 기본으로 제공하는 테스트 api이다. assertEqual(), assertNotNull(), assertTrue(), assertAll(), assertThrows(), assertTimeout() 등 여러 메서드들을 제공하며 테스트 시 비교하거나 제한을 두어 진행할 수 있도록 도와준다. Assertion 이외에 AssertJ, Hemcrest, Truth 등 다른 라이브러리를 사용해서 진행해도 무관하며 AssertJ와 Hemcrest는 SpringBoot에서 기본으로 제공해준다.

✅ assertEqual()

assertEqual(expected, actual, message) 상태의 메서드이며 message는 생략 가능하다.

첫번째 매개변수와 두번째 매개변수의 위치는 바뀌어도 테스트하는데는 문제는 없지만 해당 api를 제대로 알고 사용한다면 첫번째 매개변수는 예상하는 값, 두번째 매개변수에는 실제 테스트를 진행할 값을 넣어주면 좋다.

마지막으로 message의 경우 테스트가 실패했을 때 콘솔에 메세지를 찍어주는 역할을 해주는데.

assertEqual(expected, actual, "실패")

String type으로 사용해도 상관 없으나 만약 메세지의 크기가 성능을 좌우할 만큼 큰 내용이 들어가야한다면

assertEqual(expected, actual, ()->{return "실패";})

와 같이 supplier 매개변수도 제공해주기 때문에 다음과 같이 작성해주면 성능을 고려한 테스트 코드를 작성할 수도 있다.

여기서 왜 성능을 고려한 테스트가 되냐면 기존 String으로 message를 작성했을 땐 해당 메서드가 실행되며 메세지에 대한 메모리까지 고려해서 할당된다. 하지만 supplier를 매개변수로 작성했을 경우 테스트가 진행한 뒤 실패했을 경우에만 supplier가 실행되기 때문에 실행을 하지 않을 때는 메모리를 할당하지 않고 진행할 수 있기 때문에 성능면을 고려한 테스트가 된다.

✅ assertAll()

assertAll()을 사용하여 executable로 묶어서 사용하여 위에서 에러가 실패하더라도 한번에 묶인 테스트를 모두 실행할 수 있다.

예를 들어

@Test
void test() {
    assertEquals("String", "Strig", ()->{return "실패1";});
    assertEquals("String", "String", ()->{return "성공";});
    assertEquals("String", "Strig", ()->{return "실패2";});
}

다음과 같은 코드가 있을 때 실패1의 메세지만 출력해볼 수 있다.

하지만 assertAll()을 사용하면 테스트를 별도로 하나씩 다 진행해볼 수 있다.

@Test
void test() {
    assertAll(
            ()-> assertEquals("String", "Strig", ()->{return "실패1";}),
            ()-> assertEquals("String", "String", ()->{return "성공";}),
            ()-> assertEquals("String", "Strig", ()->{return "실패2";})
    );
}

다음과 같이 executable 매개변수로 주어 사용할 수 있고 여러 테스트를 한번에 진행할 수 있다.

실행 결과를 보면 테스트 중 2개가 실패했고 2개의 실패 내용을 확인해볼 수 있다.

✅ assertThrows

예외 테스트를 진행하고 싶을 땐 assertThrows()를 사용하면된다.

@Test
@DisplayName("테스트")
void test(){
    Car car = new Car(100);
    assertThrows(IllegalArgumentException.class, ()-> car.exception());
}

static class Car{
    int speed;

    public Car(int speed) {
        this.speed = speed;
    }

    public void exception(){
        if(true) throw new IllegalArgumentException("내가 발생시킨 exception");
    }
}

예를 들어 다음과 같은 코드가 있다고 해보자. Car라는 class를 만들었고 exception method는 무조건 exception이 발생하도록 만들었다. 그 후에 assertThrows를 사용하여 assertThrows(expectedType, executable)로 작성해주면 된다. expectedType에는 내가 예상하는 exception type의 class를 넣어주고 excutable은 내가 어떤 부분을 실행할지에 대해 넣어주면 된다.

@Test
@DisplayName("테스트")
void test(){
    Car car = new Car(100);
    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> car.exception());
    System.out.println(exception.getMessage());
}

또한 assertThrows를 변수로 받아서 해당 messgae를 찍어볼수도 있다. 이를 사용하여 assertEquals()와 같은 다른 테스트를 더 진행해볼 수 있다.

✅ assertTimeout()

실행 코드가 시간 이내에 완료가 되는지 테스트를 진행해볼 수 있다.

@Test
@DisplayName("타임 아웃")
void timeoutTest(){
    Car car = new Car(100);
    assertTimeout(Duration.ofMillis(1000), ()->{
        Thread.sleep(3000);
    });

}

다음과 같이 사용할 수 있으며 assertTimeout(duration, excutable)로 사용할 수 있다. duration에는 예상 시간을 Duration 객체를 사용하여 ms, s 등 정의해서 사용할 수 있고 excutable에는 실행할 부분을 넣어주면 된다.

assertTimeoutPreemptively()

assertTimeout의 경우 지정된 duration 시간이 지나도 excutable이 종료될때 까지 계속해서 진행되는데 assertTimeoutPreemptively()는 시간내에 종료되지 않으면 시간에 맞춰 바로 종료된다.

그러나 주의해서 사용해야한다. ThreadLocal을 사용하는 코드가 존재할 경우 예상치 못한 에러가 발생할 수 있다.

예를 들어 스프링이 만들어주는 트랜잭션은 ThreadLocal을 사용하여 롤백을 구현하고 있는데. insert 후 시간이 지나서 강제로 종료되어진다면 롤백이 안되고 디비에 반영되는 에러가 발생할 수도 있다.

profile
코딩을 깔끔하게 하고 싶어하는 초보 개발자 (편하게 글을 쓰기위해 반말체를 사용하고 있습니다! 양해 부탁드려요!) 현재 KakaoVX 근무중입니다!

0개의 댓글