JUnit
Junit이란 자바 개발자의 93%가 사용하는 단위 테스트 프레임워크이며 Java8 이상부터 지원한다.
JUnit5의 경우 2017년 10월에 공개
스프링부트의 경우 2.2버전부터 기본적으로 제공된다.
전처리 작업1(모든 테스트 실행전후 한번만)
// JUnit4
@BeforeClass, @AfterClass
// JUnit5
@BeforeAll, @AfterAll
스태틱으로 동작하기 때문에 변수에 값을 할당하고 싶다면 변수도 static으로 선언해야 한다.
import org.junit.jupiter.api.BeforeAll;
class JUnitTest {
private static String example;
@BeforeAll
static void setup() {
example = "여기서 매핑";
}
}
전처리 작업2(모든 테스트 실행전후마다 반복)
// JUnit4
@Before, @After
// JUnit5
@BeforeEach, @AfterEach
import org.junit.jupiter.api.BeforeAll;
class JUnitTest {
private String example;
@BeforeEach
void setup() {
example = "여기서 매핑";
}
}
테스트 제외
// JUnit4
@Ignore
// JUnit5
@Disabled
테스트를 작성한 코드를 수정하고 있을경우 제외를 시킴으로써 테스트를 통과시킨다.
import org.junit.jupiter.api.BeforeAll;
class JUnitTest {
@Test
@Disabled("문제가 해결될 때까지 테스트 중단")
void test() {
System.out.println("테스트1");
}
@Test
void test2() {
System.out.println("테스트2");
}
}
테스트 이름표기
// JUnit4
@Test
void 테스트_이름은_이렇게_작성한다() {
}
// Junit5
@DisplayName("굉장한 테스트 입니다.")
@Test
void test() {
}
DisplayName을 적용함으로써 이모지나 공백등의 특수문자가 들어갈 수 있게 되었다.
(부작용으로 메서드 명을 고민해야 한다.)
테스트 반복
@RepeatedTest(10)
// 해당 메서드를 10번 테스트한다.
랜덤한 요소를 체크하거나 성능상 이슈를 체크할때 주로 사용한다.
테스트 매개변수를 변경하여 테스트
@ParameterizedTest를 이용하면 인자를 바꿔가며 테스트를 할 수 있다.
범위에 대한 테스트나 경계값 테스트 등의 여러가지 테스트를 편하게 진행할 수 있다.
매개변수는 아래와 같은 방법으로 넘길 수 있다.
@ValueSource
@ParameterizedTest
@ValueSource(ints = {1, 2, 3, 4, 5})
@DisplayName("로또의 숫자 중 중복된 값이 있다면 에러가 발생한다.")
void createWhenDuplicateNumber(int number) {
}
단순히 값이 하나만 바뀔때는 ValueSource를 이용하면 쉽게 값을 바꿔가며 테스트가 가능하다.
@CsvSource
@ParameterizedTest
@CsvSource(value = {"1:true", "7:false"}, delimiter = ':')
@DisplayName("로또에 숫자의 포함여부를 확인한다.")
void contains(int number, boolean expected) {
}
여러개의 값을 넣고 테스트를 하고싶다면 CsvSource를 이용하면 된다.
value는 값들을 넣고, delimiter에 구분자를 넣어서 문자열을 분리해 매개변수에 맞는 타입으로 변환하여 주입해준다.
@MethodSource
@ParameterizedTest
@MethodSource("getReward")
@DisplayName("Reward의 당첨 횟수를 반환한다.")
void testGetRewardCountWithReward(Item item) {
// given
final Map<Reward, Integer> rewardCounter = getRewardCounter();
final LottoResult lottoResult = new LottoResult(rewardCounter);
// when
final int rewardCount = lottoResult.get(item.reward);
// then
assertThat(rewardCount).isEqualTo(item.count);
}
private static Stream<Item> getReward() {
return Stream.of(
new Item(Reward.FIRST, 1),
new Item(Reward.SECOND, 0),
new Item(Reward.THIRD, 2),
new Item(Reward.FOURTH, 4)
);
}
private static class Item {
private final Reward reward;
private final int count;
public Item(Reward reward, int count) {
this.reward = reward;
this.count = count;
}
}
CsvSource만으로 값을 표현하지 못할때가 있다.
이럴때는 MethodSource를 이용하여 처리를 하면된다.
테스트 방법
테스트야 사람마다 방법이 다르지만 내가 배운방법은 아래와 같다.
@DisplayName("test 입니다.")
@Test
void test() {
// given
// given에서는 값을 초기화 하는 등의 전처리 작업을 한다.
// when
// when에서는 우리가 목표로 하는 기능을 동작시킨다.
// then
// then에서는 우리가 원한 결과가 나왔는지 확인한다.
}
위와 같은 구조를 이용하면 테스트 코드를 보았을때 원하는 목적이 무엇인지 알기가 쉬워진다.
Assertions
테스트 케이스의 수행 결과를 판별하는 메서드이다.
@DisplayName("확장자 없는 이름이 들어간다면 zookeeper에 데이터가 있을시 확장자 이름으로 바꿔준다.")
@ParameterizedTest
@CsvSource(value = {"ato:ato.mung", "sun:sun.flower"}, delimiter = ':')
void checkUsername(String nickName, String expected) {
// given
// when
String value = memberService.checkUsername(nickName);
// then
Assertions.assertEquals(value, expected);
}
더 많은 내용은 문서로 확인하자.
https://junit.org/junit5/docs/current/user-guide/
AssertJ
테스트를 할때 JUnit에서 제공하는 Assertions말고 AssertJ를 이용할수도 있다.
AssertJ는 테스트를 더 다방면으로 테스트 할 수 있도록 도와주는 오픈소스 라이브러리이다.
testImplementation 'org.assertj:assertj-core:버전'
@ParameterizedTest
@CsvSource(value = {"1:true", "7:false"}, delimiter = ':')
@DisplayName("로또에 숫자의 포함여부를 확인한다.")
void contains(int number, boolean expected) {
// given
Lotto lotto = new Lotto(List.of(1, 2, 3, 4, 5, 6));
// when
boolean isContains = lotto.contains(number);
// then
assertThat(isContains).isEqualTo(expected);
}
Assertions와 차이는 비교할 값들을 구분해서 처리하고 있다.
// 같은지 비교
assertThat(isContains).isEqualTo(expected);
// 다른지 비교
assertThat(numbers.size()).isNotEqualTo(pivot);
// 내부 크기 비교
assertThat(lotto.getNumbers()).hasSize(EXPECTED_SIZE);
// 에러 클래스 비교
assertThatThrownBy(callable).isExactlyInstanceOf(IllegalArgumentException.class);
// 클래스 비교 + 에러 메시지 비교
assertThatThrownBy(() -> board.addComment(comment))
.isExactlyInstanceOf(GoodDayException.class)
.hasMessage(BoardExceptionSet.ALREADY_EXISTED_COMMENT.getMessage());
// true 인지 비교
assertThat(bishop.checkPositionRule(start, validDestination)).isTrue();
// false 인지 비교
assertThat(bishop.checkPositionRule(start, invalidDestination)).isFalse();
// null 비교
assertThat(board.getComment()).isNull();
// null이 아닌지 비교
assertThat(board.getComment()).isNotNull();
// 에러가 발생하지 않았는지 비교
assertThatCode(() -> board.validateUpdateBoard())
.doesNotThrowAnyException();
// 객체는 다르지만 값이 같은지 비교
assertThat(expected).usingRecursiveComparison().isEqualTo(findBoard);
더 많은 내용은 문서로 확인하자
http://joel-costigliola.github.io/assertj/assertj-core-quick-start.html
예외처리방법
// JUnit4
@Test(expected = Exception.class)
// JUnit5
@Test
void exceptionTest() {
assertThrows(Exception.class, () -> "무엇인가 실행");
}
// assertJ
assertThatThrownBy(() -> 에러발생 로직).isExactlyInstanceOf(IllegalArgumentException.class);
참고
https://www.youtube.com/watch?v=EwI3E9Natcw
'프로그래밍언어 > Java' 카테고리의 다른 글
[Java] 실행시간 측정하기 (0) | 2024.03.25 |
---|---|
[Java] try-catch-final 보다 try-with-resources를 이용하자 (0) | 2022.03.25 |
[Java] 문자열에서 원하는 문자 추출하기 (0) | 2022.02.10 |
자바(Java) String 문자열 비교하기 (0) | 2022.02.10 |
자바(Java) 문자열(String) 대문사, 소문자 변환하기 (0) | 2022.02.09 |
댓글