카테고리 없음

spring-boot(4)

rjqnrdl83 2025. 2. 11. 16:44

4. 스프링 부트3와 테스트

 

4.1 테스트 코드 개념 익히기

테스트 코드는 작성한 코드가 의도대로 잘 동작하고 예상치 못한 문제가 없는지 확인할 목적으로 작성하는 코드입니다. 유지보수에 매우 좋고 코드 수정시 기존 기능이 제대로 작동하지 않을까봐 걱정하지 않아도 된다는 장점이 있기에 꼭 공부를 해야하는 부분입니다.

 

테스트 코드란?

테스트 코드는 test디렉터리리에서 작업합니다. 테스트 코드에도 다양한 패턴이 있지만 given-when-then 패턴을 사용할 것입니다. 테스트를 세 단계로 구분해서 작정하는 방식입니다.

1. given은 테스트 실행을 준비하는 단계

2. when은 테스트를 진행하는 단계

3. then은 테스트 결과를 검증하는 단계

 

4.2 스프링 부트3와 테스트

애플리케이션을 테스트하기 위한 도구와 어노테이션을 제공합니다. spring-boot-starter-test 스타터에 테스트를 위한 도구가 모여 있습니다.

 

스프링 부트 스타터 테스트 목록

  • JUnit: 자바 프로그래밍 언어용 단위 테스트 프레임 워크
  • Spring Test & Spring Boot Test: 스프링 부트 애플리케이션을 위한 통합 테스트 지원
  • AssertJ: 검증문인 어설션을 작성하는 데 사용되는 라이브러리
  • Hamcrest: 표현식을 이해하기 쉽게 만드는데 사용되는 Matcher 라이브러리
  • Mockito: 테스트에 사용할 가짜 객체인 목 객체를 쉽게 만들고 관리하고 검증할 수 있게 지원하는 테스트 프레임워크
  • JSONassert: JSON용 어설션 라이브러리
  • JsonPath: JSOON 데이터에서 특정 데이터를 선택하고 검색하기 위한 라이브러리

이들 중에서 JUnit과 AssertJ를 가장 많이 사용합니다.

JUnit이란?

JUnit은 자바 언어를 위한 단위 테스트 프레임워크입니다.

단위 테스트: 작성한 코드가 의도대로 작동하는지 작은 단위로 검증하는 것. 단위는 보통 메서드입니다.

 

JUnit의 특징

  • 테스트 방식을 구분할 수 있는 어노테이션을 제공
  • @Test 어노테이션으로 메서드를 호출할 때마다 새 인스턴스를 생성, 독립 테스트 가능
  • 예상 결과를 검증하는 어설션 메서드 제공
  • 사용 방법이 단순하며 테스트 코드 작성 시간이 적음
  • 자동 실행, 자체 결과를 확인하고 즉각적인 피드백을 제공

 JUnit으로 단위 테스트 코드 만들기

public class JUnitTest {
    @DisplayName("1+2는 3이다")
    @Test
    public void junitTest(){
        int a=1;
        int b=2;
        int sum=3;
        Assertions.assertEquals(a+b,sum);
    }
}

@DisplayName어노테이션은 테스트 이름을 명시합니다.

@Test 어노테이션을 붙인 메서드는 테스트를 수행하는 메서드가 됩니다.

JUnit은 테스트끼리 영향을 주지 않도록 각 테스트를 실행할 때마다 테스트를 위한 실행 객체를 만들고 테스트가 종료되면 실행 객체를 삭제합니다.

검증 메서드는 assertEquals()로 a+b와 sum의 값이 같은지 확인합니다. 첫 번째 인수에는 기대하는 값, 두 번째 인수에는 검증할 값을 넣어줍니다.

 

이번에는 자주 사용하는 JUnit의 어노테이션을 알아보겠습니다.

public class JUnitCycleTest {
    @BeforeAll
    static void beforeAll(){
        System.out.println("Before All");
    }
    @BeforeEach
    public void beforeEach(){
        System.out.println("Before Each");
    }
    @Test
    public void test1(){
        System.out.println("test1");
    }
    @Test
    public void test2(){
        System.out.println("test2");
    }
    @Test
    public void test3(){
        System.out.println("test3");
    }
    @AfterAll
    static void afterAll(){
        System.out.println("After All");
    }
    @AfterEach
    public void afterEach(){
        System.out.println("After Each");
    }
}

@BeforeAll 어노테이션

전체 테스트를 시작하기 전에 처음으로 한 번만 실행합니다. 데이터베이스를 연결해야 하거나 테스트 환경을 초기화할 때 사용됩니다. 실행주기에서 한번만 호출 되어야 하기 때문에 메서드를 static으로 선언해야 합니다

 

@BeforeEach 어노테이션

테스트 케이스를 시작하기 전에 매번 실행됩니다. 테스트 메서드에서 사용하는 객체를 초기화하거나 테스트에 필요한 값을 미리 넣을 때 사용할 수 있습니다. 각 인스턴스에 대해 메서드를 호출해야 하므로 메서드는 static이 아니어야 합니다.

 

@AfterAll 어노테이션

전체 테스트를 마치고 종료하기 전에 한 번만 실행합니다. 데이터베이스 연결을 종료할 때나 공통적으로 사용하는 자원을 해제할 때 사용합니다. 전체 테스트 실행 주기에서 한 번만 호출되어야 하므로 메서드를 static으로 선언해야합니다.

 

@AfterEach 어노테이션

각 테스트 케이스를 종료하기 전에 매번 실행됩니다. 테스트 이후에 특정 데이터를 삭제해야 하는 경우 사용합니다. @BeforeEach 어노테이션과 마찬가지로 메서드는 static이 아니어야 합니다.

결과를 보면 @BeforeAll 어노테이션으로 설정한 메서드가 실행되고 그 이후에는 테스트 케이스 개수만큼 @BeforeEach   -> @Test  -> @AfterEach의 생명주기로 테스트가 진행됩니다. 모든 테스트 케이스가 끝나면 @AfretAll 어노테이션으로 설정한 메서드를 실행하고 종료됩니다.

 

AssertJ로 검증문 가독성 높이기

ASsertJJUnit과 함께 사용해 검증문의 가독성을 확 높여주는 라이브러리 입니다.

assertThat(a+b).isEqualsTo(sum);

a와 b를 더한 값이 sum과 같아야 한다는 의미로 명확하게 읽히기 때문에 코드를 읽는 사람이 헷갈리지 않습니다. 

다음은 자주 사용하는 메서드입니다.

메서드 이름 설명
isEqualTo(A) A 값과 같은지 검증
isNotEqualTo(A) A 값과 다른지 검증
contains(A) A 값을 포함하는지 검증
doesNotContain(A) A 값을 포함하지 않는지 검증
startsWith(A) 접두가사 A인지 검증
endsWith(A) 접미사가 A인지 검증
isEmpty() 비어 있는 값인지 검증
isNotEmpty() 비어 있지 않은 값인지 검증
isPositive() 양수인지 검증
isNegative() 음수인지 검증
isGreaterThan(1) 1보다 큰 값인지 검증
isLessThan(1) 1보다 작은 값인지 검증

 

4.3 제대로 테스트 코드 작성해보기

@SpringBootTest
@AutoConfigureMockMvc
class TestControllerTest {

    @Autowired
    protected MockMvc mockMvc;
    @Autowired
    protected WebApplicationContext context;
    @Autowired
    private MemberRepository memberRepository;
    @BeforeEach
    public void mockMvcSetUp(){
        this.mockMvc= MockMvcBuilders.webAppContextSetup(context).build();
    }
    @AfterEach
    public void cleanUp(){
        memberRepository.deleteAll();
    }

}

@SpringBootTest

메인 애플리케이션 클래스에 추가하는 어노테이션인 @SpringBootApplication이 있는 클래스를 찾고 그 클래스에 포함되어 있는 빈을 찾은 다음 테스트용 애플리케이션 컨텍스트라는 것을 만듭니다.

 

@AutoConfigureMockMvc

MockMvc를 생성하고 자동으로 구성하는 어노테이션입니다. MockMvc는 애플리케이션을 서버에 배포하지 않고도 테스트용 MVC 환경을 만들어 요청 및 전송, 응답 기능을 제공하는 유틸리티 클래스입니다. 즉 컨트롤러를 테스트할 때 사용되는 클래스입니다.

 

이제 TestController의 로직을 테스트하는 코드를 작성하겠습니다.

--생략--
@DisplayName("getAllMembers: 아티클 조회에 성공한다")
    @Test
    public void getAllMembers() throws Exception {
        //given
        final String url="/test";
        Member savedMember=memberRepository.save(new Member(1L, "홍길동"));
        //when
        final ResultActions result=mockMvc.perform(get(url)    //(1)
        		.accept(MediaType.APPLICATION_JSON));  //(2)
        //then
        result.andExpect(status().isOk())        //(3)
        		//(4) 응답의 0번째 값이 DB에 저장한 값과 같은지 확인
                .andExpect(jsonPath("$[0].id").value(savedMember.getId()))      
                .andExpect(jsonPath("$[0].name").value(savedMember.getName())); 
    }

}

given: 멤버를 저장합니다.

when: 멤버 리스트를 조회하는 API를 호출합니다.

then: 응답 코드가 200 OK이고, 반환값은 값 중에 0번째 요소의 id와 name이 저장된 값과 같은지 확인합니다.

(1) perform() 메서드는 요청을 전송하는 역할을 하는 메서드입니다. 결과로 ResultActions 객체를 받고 ResultActions 객체는 반환값을 검증하고 확인하는 andExpect() 메서드를 제공합니다.

(2) accept() 메서드는 요청을 보낼 때 무슨 타입으로 응답을 받을지 결정하는 메서드입니다. JSON을 받는다고 명시했습니다.

(3) anndExpect() 메서드는 응답을 검증합니다. isOk()를 사용해 응답코드가 OK(200)인지 확인합니다.

(4) jsonPath("$[0].${필드명}") JSON의 응답값의 값을 가져오는 역할을 하는 메서드입니다. 0번째 배열에 들어있는 객체의 id, name을 가져오고 저장된 값과 같은지 확인합니다.

 

HTTP 주요 응답 코드

코드 매핑 메서드 설명
200 OK isOk() HTTP 응답 코드가 200 OK인지 검증
201 Created isCreated() HTTP 응답 코드가 201 Created인지 검증
400 Bad Request  isBadRequest() HTTP 응답 코드가 400 BadRequest인지 검증
403 Forbidden isForbidden() HTTP 응답 코드가 403 Forbidden인지 검증
404 Not Found isNotFound() HTTP 응답 코드가 404 Not Found인지 검증
400번대 응답 코드 is4XXClientError() HTTP 응답 코드가 400번대 응답 코드인지 검증
500 internal Server Error isInternalServerError() HTTP 응답 코드가 500 Internal Server Error인지 검증
500번대 응답 코드 is5XXServerError() HTTP 응답 코드가 500 응답인지 검증

 

요약

1. 테스트 코드를 작성하면 코드의 기능이 제대로 작동한다는 것을 검증할 수 있습니다. 테스트 코드는 테스트를 준비하는 given, 테스트를 실제로 진행하는 when, 테스트 결과를 검증하는 then으로 구분됩니다.

2. JUnit단위 테스트를 할 때 사용하는 자바 테스트 프레임워크입니다. @BeforeAll 어노테이션으로 설정한 메서드가 실행되고 그 이후에는 테스트 케이스 개수만큼 @BeforeEach -> @Test -> @AfterEach 어노테이션으로 설정한 메서드가 실행되고 종료됩니다.

3. AssertJJUnit과 함께 사용해 검증문의 가독성을 확 높여주는 라이브러리입니다.