Junit 테스트

컨테이너·2025년 11월 6일

JAVA

목록 보기
9/9
post-thumbnail

단위테스트

소프트웨어의 특정 모듈이나 컴포넌트를 독립적으로 테스트 하는 방법을 말한다. 단위 테스트는 코드의 작은 파트를 테스트하여 특정 기능이나 메서드가 잘 작동하는지 확인한다.

어노테이션을 통한 테스트 메소드 정의

  • @Test : 테스트 메서드를 나타낸다.
  • @BeforeEach : 각 테스트 전에 실행되는 메서드를 지정
  • @AfterEach : 각 테스트 후에 실행되는 메서드를 지정한다.
  • @BeforeAll : 클래스의 모든 테스트 전에 실행되는 메서드 지정
  • @AfterAll : 클래스의 모든 테스트 후에 한 번 실행되는 메서드를 지정
  • @DisplayName : 테스트 클래스나 메서드의 이름을 지정
  • @RepeatedTest(int count) : 동일한 테스트를 여러 번 반복 실행할 때 사용

예시들과 함께 더 자세히 알아볼 것이다.

Assertions

  • Junit은 손쉽게 짧은 단위별로 테스트할 수 있도록 도와주는 효과적인 도구이다. Junit 중 어설션은 테스트 결과 를 확인하는데 사용한다.

given, when, then

테스트 코드를 작성할 때, 이 주요 세 가지 파트로 나뉘어지게 된다. Given, when, then 이라는 워딩으로 나뉘는데, 각 단어의 뜻을 간단하게 풀이해보면

/*given*/준비 단계
테스트를 위한 초기 상태(조건, 입력, Mock 등)를 세팅한다.

/*when*/실행 단계
테스트 대상 메서드나 행위를 실제로 수행한다.

/*Then*/검증 단계
그 결과가 기대한 대로 나왔는지 단언(assert)한다.

1. assertEquals : 예상 값과 실제 값의 일치 여부를 동일성으로 판단한다.

void testAssertEquals() {

    /* given:  */
    
    int firstNum = 10;
    int secondNum = 20;
    int expected = 34;
    
    /* when 어떤 것을 하는가?*/
    
    Calculator calculator = new Calculator();
    int result = calculator.plus(firstNum, secondNum);
	
    /* then */
    
Assertions.assertEquals(expected, result, delta:5); // 두 수를 더하고 결과값과 확인해보겠다
    // delta = 근사치(오차범위) 허용
Assertions.assertNotEquals(firstNum, secondNum); // 부정 단정 -> 틀리면 성공하는것

2. assertNull Null 여부 테스트

@Test
@DisplayName("Null 여부 테스트")
void testAssertNulls() {
    /*given*/
    String str = null;
    /*when*/
    /*then*/
    //Assertions.assertNotNull(str);//null인가?
    Assertions.assertNull(str);
}

3. assertAll : 한 번에 여러 검증을 수행할 수 있는 메소드

@Test
@DisplayName("동시에 여러 값에 대한 검증 테스트")
void testAssertAll() {
    /*given*/
    String firstName = "길동";
    String lastName = "홍";
    Person person = new Person(firstName, lastName);
    /*when*/
    /*then*/
    Assertions.assertAll(
            "그룹화 된 테스트의 이름(테스트 실패 시 보여지는 부분)",
            //() -> Assertions.assertEquals("", person.getFirstName()),//여기서 틀렸음-> header 부분이 출력된다.
            () -> Assertions.assertEquals(firstName, person.getFirstName()),
            () -> Assertions.assertEquals(lastName, person.getLastName()
    );

틀린 화면 :

맞은 화면 :

4. assertThrows/assertInstanceOf : 이게 뭐지

@Test
@DisplayName("예외발생 테스트")
void testAssertThrow() {
    /*given*/
    int firstNum = 10;
    int secondNum = 0;
    /*when*/
    NumberValidation validation = new NumberValidation();
    // Exception 클래스 가져오기
    Exception exception = Assertions.assertThrows(
        IllegalArgumentException.class,
            () -> validation.checkDividableNumbers(firstNum,secondNum)
    );
    /*then*/
    Assertions.assertAll(
            // 예외가 실제로 일어났는가?
            () -> Assertions.assertInstanceOf(
                    IllegalArgumentException.class,
                    exception
            ),
            // 예외 메시지가 동일한가?
            () -> Assertions.assertEquals(
                    "0으로 나눌 수 없습니다.",
                    exception.getMessage()
            )
    );

Test 서드파티라이브러리 사용법

  1. 문자열 테스트
@Test
@DisplayName("문자열 테스팅")
void testStringValidation() {
    /*메소드 체인으로 하나하나 확인해볼 수 있다.*/
    /*given*/
    String expected = "hello world";
    /*when*/
    String actual = new String(expected);
    /*then*/
    Assertions.assertThat(actual)
            .isNotEmpty()
            .isNotBlank()
            .contains("hello")
            .doesNotContain("hahahahha")
            .startsWith("h")
            .endsWith("d")
            .isEqualTo(expected);
}
  1. 숫자 테스트
@Test
@DisplayName("숫자 테스트")
void testIntegerValidation() {
    /*given*/
    double pi = Math.PI;
    Double actual = Double.valueOf(pi);
    /*when*/
    /*then*/
    Assertions.assertThat(actual)
            .isPositive() //양수인가
            .isGreaterThan(3)
            .isLessThan(5)
            .isEqualTo(Math.PI);
}
  1. 날짜 테스트
@Test
@DisplayName("날짜 테스트 하기")
void testLocalDateTimeValidation() {
    /*given*/
    String birthDay = "1999-02-12T02:03:33.135";
    LocalDateTime bDay = LocalDateTime.parse(birthDay); //Parse ->  문자열to날짜형
    Assertions.assertThat(bDay)
            .hasYear(1999)
            .hasMonthValue(2)
            .hasDayOfMonth(12)
            .isBetween("1999-02-01T02:03:33.135","1999-12-12T02:03:33.135")
            .isBefore(LocalDateTime.now())
            .isAfter("1999-02-01T02:03:33.135");
}
  1. 예외 테스트
@Test
@DisplayName("예외테스트")
void testExceptionValidation() {
    Throwable thrown = AssertionsForClassTypes.catchThrowable(() -> {
       throw new IllegalArgumentException("잘못된 파라미터를 입력하였습니다.");
    });
    Assertions.assertThat(thrown)
            .isInstanceOf(IllegalArgumentException.class)//클래스가 해당 예외 매개
            .hasMessageContaining("파라미터");
}
  1. 필터를 이용한 단정문 테스트
@Test
@DisplayName("filtering assertions 테스트")
void testFilteringAssertions() {
    /*given*/
    Member member1 = new Member(1,"user01","홍길동",16);
    Member member2 = new Member(2,"user02","이순신",26);
    Member member3 = new Member(3,"user03","신사임당",36);
    List<Member> members = Arrays.asList(member1, member2, member3); //각 멤버 객체를 List로
    /*when*/
    /*then*/
    Assertions.assertThat(members)
            .filteredOn(member->member.getAge()>19)
            .containsOnly(member2, member3) // 위 필터 결과에 member들이 포함되어 있는가? -> member1은 실패 뜸(19세미만)
            .filteredOn("age", 26) // age==26이 존재하는가?
            .containsOnly(member2); //위 모든 조건을 member2 가 통과하는가?
}

어노테이션 확인해보기

  • 테스트 수행 전 필요한 자원을 설정하는 역할의 메소드

@BeforeAll

  • 하나씩 돌아준다. 얘는 static으로 만들어줘야함. 왜냐하면 실행전에 한 번씩 싹 돌아줘야함

@afterAll

  • 작동 후 체크

각 어노테이션 확인 - 자원과 체크 타이밍 확인(생명주기 확인 어노테이션)

public class LifeCycleAnnotationTests {
    /*테스트 메소드 확인 전 어노테이션 먼저 확인해보자*/
    /*before all*/
    static void beforeAll() {
        System.out.println("before all 동작");//클래스의 모든 테스트 전에 한 번 실행되는 메서드를 지정한다
    }
    /*before each*/
    void beforeEach() {
        System.out.println("before each 동작");
    }
    @BeforeAll
    static void before() {
        System.out.println("beforeall");
    }
    @BeforeEach
    void beforeEach1() {
        System.out.println("beforeEach1");
    }
    @AfterAll
    static void afterAll() {
        System.out.println("afterAll");
    }
    @AfterEach
    void afterEach1() {
        System.out.println("afterEach1");
    }
    @Test
    void test1() {
        System.out.println("테스트 코드1");
    }
    @Test
    void test2() {
        System.out.println("테스트 코드1");
    }
}

결과

beforeall
beforeEach1
테스트 코드1
afterEach1
beforeEach1
테스트 코드1
afterEach1
afterAll

추가적인 부분

@Disabled : 테스트 무시 → 테스트가 진행되지 않고 무시된다.

@Timeout(value = 시간) : 제한시간 지나면 오류

@Test
@Timeout(value = 1)
void testTimeOut() {
    try {
        Thread.sleep(9900);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    System.out.println("타임아웃 테스트");
}

Order(순서int) : 실행 순서 설정

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class AdditionalAnnotationTests {
  • Order() 어노테이션을 사용하려면 위와같이 클래스레벨 어노테이션을 선언해 주어야 한다.
@Test
@Order(1)
void testFirst() {
    System.out.println("first");
}
@Test
@Order(3)
void testSecond() {
    System.out.println("second");
}
@Test
@Order(2)
void testThird() {
    System.out.println("third");
}

# 결과

first
third
second

@RepeatedTest(반복횟수) : 테스트를 반복한다.

@RepeatedTest(10)
    void testRepeated() {
        System.out.println("반복 테스트");
    }
    
# 결과

반복 테스트
반복 테스트
반복 테스트
반복 테스트
반복 테스트
반복 테스트
반복 테스트
반복 테스트
반복 테스트
반복 테스트
profile
백엔드

0개의 댓글