Written by
Poogle
on
on
테스트 주도 개발
참고: 책 “테스트 주도 개발 시작하기 - 최범균 저”
Test Code
- TDD는 테스트부터 시작, 테스트를 먼저 하고 그 후에 구현
- 테스트를 먼저 한다는 것은 기능이 올바르게 동작하는지 검증하는 테스트 코드를 먼저 작성한다는 것을 의미
JUnit
- 프로덕션 코드와 테스트 코드가 분리 되어야 함(테스트가 서비스하는 시점에 같이 배포할 필요는 없으니)
- 내가 관심을 가지는 메소드에 대한 테스트 가능
- 로직을 실행한 후의 결과 값 확인을 프로그래밍을 통해 자동화 하는 것이 가능
- 단위 테스트 프레임워크 중 하나
한 번에 메소드 하나에만 집중
@Test
어노테이션 추가- 테스트 메소드를 독립적으로 실행할 수 있음 → 현재 내가 구현하고 있는 프로덕션 코드의 메소드만 실행해볼 수 있음
- 다른 메소드에 영향을 받지 않기 떄문에 내가 현재 구현하고 있는 프로덕션 코드에 집중할 수 있음
결과 값을 눈이 아닌 프로그램을 통해 자동화
main()
메소드: 실행 결과를 직접 눈으로 확인해야 함
⇒ assertEquals()
메소드 제공
- 첫 번째 인자: 기대하는 결과 값(expected)
- 두 번째 인자: 프로덕션 코드의 메소드를 실행한 결과 값(actual)
assertEquals()
,assertTrue()
,assertFalse()
,assertNull()
,assertNotNull()
테스트 코드 중복 제거
@Before
어노테이션을 활용- 필드로 구현하는 방법과 다름 없이 단위테스트를 실행할 때마다 인스턴스를 생성
- 그런데 테스트 메소드 간에 영향을 미칠 경우 테스트 실행 순서나 상태 값에 따라 테스트가 성공하거나 실패할 수 있음
- JUnit은
@RunWith
,@Rule
같은 어노테이션을 사용해 기능을 확장할 수 있어서@Before
안 이어야만 위에서 초기화된 객체에 접근할 수 있음
@After
: 후처리 작업 담당- 각 테스트 간 영향 안 미치면서 독립적인 실행이 가능하도록 지원
참고: https://gmlwjd9405.github.io/2019/11/27/junit5-guide-parameterized-test.html
@ParameterizedTest
@ValueSource
- 해당 어노테이션에 지정한 배열을 파라미터 값으로 순서대로 넘겨줌
- 테스트 메소드 실행 당 하나의 인수만을 전달할 때 사용
- 리터럴 값의 배열을 테스트 메서드에 전달
@ParameterizedTest
@DisplayName("5자 이하의 이름을 가진 자동차 생성 테스트")
@ValueSource(strings = {"pobi", "crong", "honux"})
void createCarWithName(String name) {
car = new Car (name);
assertThat(car.getName()).isEqualTo(name);
}
@MethodSource
- 보다 복잡한 인수를 제공하는 방법으로 method를 argument source로 사용
@MethodSource
에 설정하는 이름은 존재하는 메서드 이름- argument source method 조건
- Stream
(혹은 Iterable, Iterator) 또는 List와 같은 컬렉션과 유사한 interface 를 반환할 수 있다. - 클래스 단위 생명 주기가 아닌 경우, static method 여야 한다.
- Stream
@MethodSource
를 이용하면 다른 테스트 클래스 간에 인수를 공유하는 것이 유용하다.- 이 경우 정규화된 이름 (FQN#methodName format)으로 현재 클래스 외부의 source method 를 참조할 수 있다.
static Stream<Arguments> distances() {
return Stream.of(
Arguments.of(new MoveStrategy[]{() -> false, () -> false, () -> false}, new Car(carName, 0)),
Arguments.of(new MoveStrategy[]{() -> true, () -> true, () -> true}, new Car(carName, 3)),
Arguments.of(new MoveStrategy[]{() -> true, () -> false, () -> true}, new Car(carName, 2))
);
}
@ParameterizedTest
@DisplayName("이동거리 확인 테스트")
@MethodSource("**distances**")
void checkPosition(MoveStrategy[] positions, Car expected) {
for (MoveStrategy moveStrategy : positions) {
car = car.move(moveStrategy);
}
assertEquals(expected, car);
}