카테고리 없음

기능명세로서의 테스트코드 및 JUnit 기본

codingtori 2025. 9. 25. 11:07

설계 과정을 지원하는 TDD

 

테스트를 만들려면?

1. 테스트할 기능 실행

    - 클래스, 메서드, 함수이름

    - 파라미터

2. 결과를 검증

    - 리턴 값

 

이러한 과정에서 이름을 고민하고 파라미터 타입과 리턴 타입을 고민한다. 이것이 곧 설계 과정이다.

이름은 설계에서 매우 중요하며, 이름이 기대하는 것과 다르게 동작할 경우 코드 분석 시간을 중가시키므로 잘 정하는 것이 중요하다

 

테스트 코드 작성 시,

파라미터와 결과 값을 정해야함 → 요구사항 문서에서 기능의 입력과 결과 도출 필요

구현 시 애매한 점의 경우 구체적으로 정리 필요 

→ 구체적인 예를 통해서 모호함이 줄어들고, 구체적인 명세가 된다

 

주의 사항 - 필요할 것으로 예측해서 미리 코드를 만들면 안됨 (설계도 마찬가지)

                 요구사항 분석 과정에서 설계를 진행


JUnit 5

JUnit5의 요소

●  JUnit 플랫폼

    : 테스팅 프레임워크를 구동하기 위한 런처와 테스트 엔진을 위한 API 제공

    ○  junit-platform-launcher ▷ junit-platform-engine

●  JUnit 주피터(Jupiter)

    : JUnit5를 위한 테스트 API와 실행엔진 제공

    ○  junit-jupiter-engine ▷ junit-jupiter-api

  JUnit 빈티지(Vintage)

    : JUnit 3과 4로 작성된 테스트를 JUnit5 플랫폼에서 실행하기 위한 모듈을 제공

    ○  junit-vintage-engine ▷ junit:junit

 

JUnit5 는 테스트를 위한 API로 주피터 API 제공

사용하기 위해서 주피터 관련 모듈 의존에 추가

1. junit-jupiter-api

2. junit-jupiter-params

3. junit-jupiter-engine

 

JUnit5를 이용해서 테스트 실행할 경우 JUnit5가 제공하는 플랫폼 런처 사용 필요

maven의 경우 → maven-surefire-plugin 2.22.0 버전부터 JUnit5 플랫폼 지원

 

<dependencies>
	<dependency>
    	<groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.5.0</version>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
	<plugins>
    	<plugin>
        	<artifactId>maven-surefire-plugin</artifactId>
            <version>2.22.1</version>
        </plugin>
        ...
    </plugins>
</build>

 


JUnit의 Assertions 클래스

값을 검증하기 위한 목적의 다양한 정적 메서드 제공

 

주요 단언 메서드 정리

메서드 설명
assertEquals(expected, actual) 실제 값(actual)이 기대하는 값(expected)와 같은 지 검사
assertNotEquals(unexpected, actual) 실제 값(actual)이 특정 값(unexpected)과 같지 않은 지 검사
assertSame(Object expected, Object actual) 두 객체가 동일한 객체인지 검사
assertNotSame(Object unexpected, Object actual) 두 객체가 동일하지 않은 객체인지 검사
assertTrue(boolean condition) 값이 true 인지 검사
assertFalse(boolean condition) 값이 false인지 검사
assertNull(Object actual) 값이 null인지 검사
assertNotNull(Object actual) 값이 null이 아닌지 검사
fail() 테스트를 실패 처리

 

fail() 메서드의 경우, 테스트에 실패했음을 알리고 싶을 때 사용 - 특히 익셉션 발생 유무를 검증할 때 많이 사용

 

익셉션 발생 유무 검사 메서드

메서드 설명
assertThrows(Class<T> expectedType, Executable executable) executable을 실행한 결과로 지정한 타입의 익셉션이 발생하는지 검사
assertDoesNotThrow(Executable executable) executable을 실행한 결과로 익셉션이 발생하지 않는지 검사

 

예시 코드

IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
    () -> {
    	AuthService authService = new AuthService();
        authService.authenticate(null, null);
    });
    
// 추가 검증
assertTrue(thrown.getMessage().contains("id"));

 

※ 참고 - Executable 인터페이스

              : execute 함수를 가진 함수형 인터페이스

package org.junit.jupiter.api.function;

public interface Executable{
	void execute() throws Throwable;
}

 

 

assertAll()

일단 모든 검증을 실행하고 그중에 실패한 것이 있는지 확인

Executable 목록을 가변인자로 받아서 각 Executable을 수행하는 것

assertAll(
    () -> assertEquals(3, 5/2),
    () -> assertEquals(4, 2*2),
    () -> assertEquals(6, 11/2)
);

테스트 라이프사이클

 

@BeforeEach, @AfterEach

1. 테스트 메서드를 포함한 객체 생성

2. @BeforeEach 존재 시, 해당 어노테이션이 붙은 메서드 실행

3. @Test 어노테이션이 붙은 메서드 실행

4. @AfterEach 존재 시, 해당 어노테이션이 붙은 메서드 실행

 

※ @Test, @BeforeEach, @AfterEach 어노테이션을 붙인 메서드는 private이면 안됨

 

 

@BeforeAll, @AfterAll

한 클래스의 모든 테스트 메서드가 실행되기 전/후에 특정 작업을 수행해야 하는 경우

 

JUnit은 테스트 메서드의 실행 순서를 지정할 순 있지만, 각 테스트 메서드는 서로 독립적으로 동작해야하는 것임. 의존성이 생길경우 유지보수에 어려움이 생김

 

++)

@DisplayName : 메서드 이름 붙이기

@Disabled : 특정 테스트를 실행하지 않고 싶을 때  -- 테스트 코드가 완성되지 않았거나 잠시동안 테스트를 실행하지 말아야 할 때

import org.junit.jupiter.api.Disabled;

public class AssertionsTest {
    @Disabled
    @Test
    void failMethod() {
    	try{
        	AuthService authService = new AuthService();
            authService.authenticate(null, null);
           	fail();
        } catch (IllegalArgumentException e) {
        }
    }
}

 

모든 테스트를 실행하는 방법

●  maven :  mvn test 

●  gradle :  gradle test