⚡ 생각대로 살지 않으면 사는대로 생각한다.
⚡ 나는 어차피 잘 될 놈이다. 이미 잘 되고 있고, 계속해서 잘 되고 있다.

Assertions

테스트메서드설명
assertNotNull괄호 안의 값이 null인지 아닌지 확인
assertEquals실제 값이 기대한 값과 같은지 확인
assertTrue다음 조건이 참(True)인지 확인
assertNotNull(actual)값이 null이 아닌지 확인
assertNull(actual)값이 null인지 확인

assertEquals

  • 괄호 안의 첫번째 값과, 두번째 값이 같은지 확인하고, 세번째에 문자열로 테스트 실패시 실패 이유나 원인을 적어놓으면, 더욱 알아보기 쉽다.

  • 첫번째 값과 두번째의 비교하는 값들의 순서를 아무렇게나 써도 상관은 없지만, 소스코드를 보면, 왼쪽이 expected, 오른쪽이 actual로 나와있다.
    즉 첫번째 값이 기대하는 값, 두번째 값이 실제 나오는 값을 적어주면 된다...
    (사실 비교해서 같은지 확인한다면 순서는 딱히 상관없지만, 명확하게 의미를 알고 쓰기 위해선, 알아둬야 할 내용인 거 같다.
    JUnit API를 이해하고 있는 분들에게는 보다 정돈된 느낌일 것이라고 강의 제공자는 말한다..)

  • 세번째 값은 Supplier 타입이 들어간다. 테스트 실패시 출력해주는 메세지를 지정한다.
    String형태로 줄 수도 있고, 람다로 줄 수도 있다.

assertEquals(StudyStatus.DRAFT, study.getStatus(), new Supplier<String>() {
@Override
public String get() {
return "스터디를 처음 만들면 상태값이 DRAFT여야 한다.";
}
});

이런식으로...해줄 수 있다.

그런데... 위와 같이 굳이 복잡하게 하지 않아도 된다. 인텔리제이에서 우클릭 후, 옵션을 줘서 replace 해주면 람다로 바꿔준다.
assertEquals(StudyStatus.DRAFT, study.getStatus(), () -> "스터디를 처음 만들면 상태값이 DRAFT여야 한다.");
이 코드처럼 바꿔준다.

assertEquals(StudyStatus.DRAFT, study.getStatus(), "스터디를 처음 만들면 상태값이 DRAFT여야 한다.");
assertEquals(StudyStatus.DRAFT, study.getStatus(), "스터디를 처음 만들면 " + StudyStatus.DRAFT + " 상태다.");
assertEquals(StudyStatus.DRAFT, study.getStatus(), () -> "스터디를 처음 만들면 " + StudyStatus.DRAFT + " 상태다.");
이 세 코드는 결국 같은 내용이지만, 내부적으로 처리 방법이 다르다.
위의 두 줄은 문자열 연산을 매번한다. 테스트가 실패를 하던, 성공을 하던간에...
하지만 세 번째 줄처럼 람다식 형식으로 작성된 경우, 연산처리를 최대한 안 하게 되고, 최대한 필요한 시점에만 연산을 한다.
테스트가 실패할 때만 연산을 실행한다.
성능적으로 쌩 문자열을 넣는 것 보다 더 효율적이다.

✅하나의 테스트메서드에 assert문들이 여러개 있으면 코드가 순차적으로 실행되는데, 그 중 하나라도 실패하면, 그 테스트메서드는 아예 실패로 나온다.


이렇게 말이다...즉,
이런식으로, 하나가 막히면 실패가 바로 나오고, 통과를 해야 그 다음 테스트메서드가 실행된다.
실패했다면, 다음 assert문은 실행되지 않은 채 실패를 알려준다.

그런데 assert문들을 한번에 묶어줄 수 있는 것이 있는데 바로, assertAll로 묶어줄 수 있다.
assertAll 안에 세개의 assert문을 람다식으로 이런식으로 묶어줄 수 있다.

assertAll(
	() -> assertNotNull(study),
	() -> assertEquals(StudyStatus.DRAFT, study.getStatus(),
		() -> "스터디를 처음 만들면 " + StudyStatus.DRAFT + " 상태다."),
	() -> assertTrue(study.getLimit() > 0, "스터디 최대 참석 가능 인원은 0보다 커야 한다.")
);

원래는 하나의 테스트가 실패하면, 실패를 결과로 주고, 다음 코드를은 실행하지 않았는데, 이렇게 assertAll로 묶어주면,
하나의 테스트 메서드의 결과가 실패이더라도, 다음 코드의 테스트 성공/실패여부를 확인할 수 있다.. 아래의 그림처럼..


assertThrows(예외클래스(*.class), 실행 메서드(람다식으로 가능))

해당 메서드를 실행할 때, 지정한 예외가 발생하는지 확인.
만약 Study 클래스에 이런 코드가 있을 때,

예외를 통해서 발생하는 메세지가 내가 생각하는 메세지와 같은지 이런식으로 확인 가능하다.

assertTimeout(duration, executable)

duration으로 지정한 시간 안에 executable 실행이 끝나야한다.
혹여 다음과 같은 코드가 있다고 가정하면,

assertTimeout(Duration.ofMillis(100), () -> {
           new Study(10);
           Thread.sleep(300);
});

시간을 체크해서 테스트를 하는데, 이 코드같은 경우, Thread.sleep(300)코드로 인해서 300 Mili초를 다 기다려야한다. 아래그림처럼..

그런데, 테스트에서는 100 Mili초 안에 끝나지 않는다면, 어차피 테스트는 실패하기 때문에, 굳이 300 Mili초까지 기다릴 필요가 없다!!
이때, assertTimeout이 아니라, assertTimeoutPreemptively를 사용하면, 굳이 300 Mili초까지 기다릴 필요없이, 어차피 100 Mili초가
지나면, 테스트가 실패하기 때문에, 지정한 시간 근처에서 테스트의 실패를 알려준다.
(위 사진과 시간을 비교해보면 된다.)

💡 단! assertTimeoutPreemptively를 사용한다면, ThreadLocal은 공유가 되지 않기 때문에, 테스트를 하다가 rollback이 되지 않아서, DB에 반영이 되는 경우가 있다고 한다. 예상치 못 한 상황이 발생할 수 있기 때문에, 주의가 필요하다고 한다.

그 외 다른 내용들은 org.junit.jupiter.api.Assertions라이브러리에서 확인 가능하고,
JUnit 외에 테스트를 위한 라이브러리 중, 그 중 AssertJ, Hemcrest, Truth 라이브러리가 있다.
그 중 AssertJ, Hemcrest은, spring-boot-starter 에 기본적으로 내장되어있다....

-끝-

profile
쌩수 Git >> https://github.com/SsangSoo?tab=repositories

0개의 댓글