View

[Java] JUnit5 - Assertion

짱호 2020. 7. 11. 19:37
반응형

1. JUnit5 - Assertion

JUnit Jupiter는 다양한 Assertion 메서드가 포함되어있다. Assertion 클래스를 살펴보면 메서드는 모두 static 메서드이고, 오버로딩을 통해 다양한 타입을 지원하고 있다.

 

다양한 Assertion 메서드를 살펴보자.

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

 

  • assertNotNull(actual)
    • 실제 값이 null이 아닌지 확인

 

  • assertTrue(boolean)
    • 다음 조건이 True인지 확인

 

  • assertAll(executables)
    • 모든 구문을 확인
    • functional Interface인 excutables 타입을 매개변수로 받는다.

 

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

 

  • assertTimeout(duration, executable)
    • 특정 시간안에 실행이 완료되는지 확인

 

Supplier와 람다식

마지막 매개변수로 message를 String형태로 생성하여 메시지를 출력할 수 있다.

예를들면 아래의 코드와 같이 테스트 결과와 함께 메시지를 출력할 수 있다.

@Test
@DisplayName("스터디 시작")
void start_study() {
    Study study = new Study();
    assertNotNull(study);

    // 메시지를 String 형태로 생성하면, 테스트가 성공하던 실패하던 문자열 연산을 매번 실행한다.
    assertEquals(StudyStatus.DRAFT, study.getStatus(), 
    		"스터디를 처음 시작하면 " + StudyStatus.DRAFT + " 상태다.");

 

위와 같이 메시지를 String 형태로 제공하게 되면 메시지를 출력할 수 있다. 하지만 이는 테스트의 실패, 성공 관계없이 문자열 연산을 실행한다.

 

만약 복잡한 문자열 연산이 들어가거나, 성능을 조금이라도 고려하는 테스트라면 Supplier<String> 타입의 인스턴스를 이용해서 이러한 연산을 비용을 줄일 수 있다.

 

Supplier<T>는 Functional Interface이다. 이를 사용하게 되면 테스트가 실패한 시점에만 호출되어 연산을 실행하기 때문에 연산 비용을 줄일 수 있는 것이다. 매개변수는 없고 리턴타입만 가지고있다.

 

Supplier<T>를 이용하여 위와 같은 연산을 표현하면, 아래와 같은 코드를 만들 수 있다.

@Test
@DisplayName("스터디 시작")
void start_study() {
    Study study = new Study();
    assertNotNull(study);
		
	
    // Supplier를 이용한 메시지
	
   assertEquals(StudyStatus.DRAFT, study.getStatus(), new Supplier<String>() {
   	@Override
   	public String get() {
       		return "스터디를 처음 만들면 DRAFT 상태다.";
   	}
   });
}

 

하지만 위와 같이 메시지를 생성하면 비용은 줄일 수 있지만 코드가 길어지는 단점이 있다. 이 또한 Java 8에서 추가된 람다식을 이용하면 코드를 간결하게 표현할 수 있게 된다.

@Test
@DisplayName("스터디 시작")
void start_study() {
    Study study = new Study();
    assertNotNull(study);
		
	
    // 람다식을 사용하면 간결한 표현이 가능하다.
    assertEquals(StudyStatus.DRAFT, study.getStatus(), () -> "스터디를 처음 만들면 DRAFT 상태다.");
}

 

AssertAll() 메서드

한 테스트에 여러개의 assert 메서드를 이용해 테스트를 진행할 때, 최상단의 assert 메서드에서 테스트가 깨지면 그 아래 테스트 코드는 실행되지 않기 때문에 값에 대한 명확한 검증이 어려워진다.

 

예를들면,

@Test
@DisplayName("스터디 시작")
void start_study() {
    Study study = new Study();

    assertNotNull(study); // <- 여기서 오류 발생시 밑의 코드는 실행되지 않는다.
    assertEquals(StudyStatus.DRAFT, study.getStatus(), () -> "스터디를 처음 만들면 DRAFT 상태다.");
    assertTrue(study.getLimit() -> 0, "스터디 인원 수는 0보다 커야합니다");
}

 

위와 같은 경우에는 assertNotNull(study); 이후의 테스트가 깨지는지 검증할 방법이 없다. 이러한 문제를 해결하기 위해서는 assertAll() 메서드를 이용하면 된다.

assertAll 메서드안에 assert 메서드를 선언해 사용할 경우 오류가 발생해도 모든 assert 메서드를 실행하게 된다.

@Test
@DisplayName("스터디 시작")
void start_study() {
    Study study = new Study();
		
    assertAll(
    	() -> assertNotNull(study),
        () -> assertEquals(StudyStatus.DRAFT, study.getStatus(), 
        				() -> "스터디를 처음 만들면 DRAFT 상태다."),
        () -> assertTrue(study.getLimit() -> 0, "스터디 인원 수는 0보다 커야합니다")
    );
}

 

위와 같이 assertAll 메서드를 이용하면 각 값에 대한 명확한 테스트 결과를 알 수 있게 된다.

 

반응형
Share Link

인기 글

최신 글

전체 방문자

Today
Yesterday