2 minute read

우테코 첫 미션으로 TDD 기법을 사용해 자동차 경주 게임을 구현한다.
이전에 프로덕션 코드를 작성하고 간단한 단위 테스트 코드를 작성한 적은 있지만 TDD는 처음이다.
지금까지는 Junit은 테스트 코드를 작성하게 지원해주는 라이브러리 정도라고만 알고 있었는데, Junit에 대해 궁금증이 생겨 정리해보았다.

Junit5

Junit5는 이전 버전과 다르게 세개의 서브 프로젝트로 이루어져 있다. Junit5은 Junit Platform + Junit Jupiter + Junit Vintage 이 3개가 합쳐진 것이다.

  • Junit Platform
    Junit Platform은 JVM 테스트 프레임워크를 실행하는데 기초를 제공한다. 또한 TestEngine API를 제공해 테스트 프레임워크를 개발할 수 있다.

  • Junit Jupiter
    Junit Jupiter는 Junit 5에서 테스트를 작성하고 확장 하기 위한 새로운 프로그래밍 모델과 확장 모델의 조합이다.

  • Junit Vintage
    Junit Vintage는 하위 호환성을 위해 Junit3과 Junit4를 기반으로 돌아가는 플랫폼에 테스트 엔진을 제공한다.


@DisplayName

테스트 클래스나 테스트 메서드에 이름을 붙여줄 때 사용한다. 테스트를 실행했을 때, 디폴트값은 메서드 이름인데, @DisplayName을 붙여주면 @DisplayName의 내용이 출력된다.


@BeforeEach

각각 테스트 메서드가 실행되기전에 실행되어야 하는 메서드를 명시해준다. @Test, @RepeatedTest, @ParameterizedTest, @TestFactory 가 붙은 테스트 메서드가 실행하기 전에 실행된다. Junit4의 @Before 와 같은 역할을 한다.


@ParameterizedTest

파라미터화 테스트는 각각 다른 인자로 여러 번 테스트를 돌린다. 호출 시 사용될 인자를 적어도 하나는 적어줘야 한다.

	@ParameterizedTest
	@ValueSource(ints = {1, 2, 3})
	@DisplayName("Set값 전체 존재 확인")
	public void set값_전체_존재_확인(int value) {
		assertThat(numbers.contains(value)).isTrue();
	}
  • @ValueSource : 간단하게 하나의 배열로 값을 정의하며, 하나의 인자만 받는 파라미터화 테스트에만 적용할 수 있다.
  • @NullSource : @ParameterizedTest 메서드에 null을 제공한다.
  • @EmptySource : 배열 같은 인자에 빈값을 제공한다.


@CsvSource

@CsvSource 는 리스트를 delimeter 속성의 구분자로 구분해 준다. delimeter 속성에 아무것도 입력하지 않는다면 기본값은 콤마를 사용한다. delimeterString 속성을 쓰면 문자 대신 문자열로 구분자를 사용할 수도 있다. 그러나 delimeter 속성과 delimeterString을 동시에 사용하면 안된다.

@ParameterizedTest
	@CsvSource(value = {"1:true", "2:True", "3:true", "4:false", "5:false"}, delimiter = ':')
	@DisplayName("Set값 존재 여부 구별")
	public void set값_존재_여부_구별(int value, boolean result) {
		assertThat(numbers.contains(value)).isEqualTo(result);
	}


Assertions

JUnit Jupiter는 JUnit4로부터 온 assertion 메소드와 새롭게 자바 8 람다 표현식으로 추가된 메소드들이 있다. 모든 JUnit Jupiter assertion은 정적 메소드이며, org.junit.jupiter.api.Assertions 클래스 안에 있다.


AssertJ란 무엇인가

AsserJ는 많은 assertion을 제공하는 자바 라이브러리다. 에러 메세지와 테스트 코드의 가독성을 매우 높여준다. Junit에서 제공하는 assertEquals에 비해 가독성이 더 좋다.

assertEquals(expected, actual);
assertThat(actual).isEqualTo(expected);


Exception 처리 test

  • assertThatThrownBy() 예외 처리를 가독성 있게 테스트할 수 있게 해준다. 기존에는 Throwable을 가지고 검증 했다면, 좀 더 나은 가독성으로 작성하게 해준다.
@Test
	public void 공백_이름() {
		assertThatThrownBy(() -> new Car(""))
			.isInstanceOf(IllegalArgumentException.class)
			.hasMessage(EMPTY_NAME_ERROR);
	}


  • assertThatExceptionOfType
	@Test
	@DisplayName("IndexOutOfBoundsException 발생")
	public void indexOutOfBoundsException_발생() {
		assertThatExceptionOfType(IndexOutOfBoundsException.class).isThrownBy(() -> {
			String input = "abc";
			int errorIndex = 5;
			String result = String.valueOf(input.charAt(errorIndex));
		});
	}


AssertJ에서 자주 발생하는 예외들에 대해 정의된 함수를 제공한다. NullPointerException, IllegalArgumentException, IllegalStateException, IOException이 있다.

  • assertThatIoException
	@Test
	@DisplayName("Exception Message 검사")
	public void exception_message_검사() {
		assertThatIOException().isThrownBy(() -> {
			throw new IOException("exception message test");
		}).withMessage("exception message test");
	}
}


참고
https://pjh3749.tistory.com/241
https://donghyeon.dev/junit/2021/04/11/JUnit5-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C/

Categories:

Updated: