Spring, Spring boot

Spring Boot3 와 테스트

ron_nie 2023. 12. 24. 14:27
728x90

테스트 코드?

테스트 코드란 작성한 코드가 의도대로 잘 동작하고 예상치 못한 문제가 없는지 확인할 목적으로 작성하는 코드

테스트 코드의 패턴

given-when-then 패턴을 사용한다. 이 패턴은 테스트 코드를 세 단계로 구분해 작성하는 방식이다

  1. given : 테스트 실행을 준비하는 단계
  2. when : 테스트를 진행하는 단계
  3. then : 테스트 결과를 검증하는 단계

JUnit을 사용한 테스트

JUnit이란?

자바 언어를 위한 단위 테스트 프레임워크

단위 테스트?

작성한 코드가 의도대로 작동하는지 작은 단위로 검증하는 것. 이때 단위는 보통 메서드가 된다.

JUnit특징

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

JUnit 사용해보기

import org.junit.jupiter.api.Assertions; 
import org.junit.jupiter.api.DisplayName; 
import org.junit.jupiter.api.Test;

public class JUnitTest {
@DisplayName("1 + 2는 3이다") // 테스트 이름
@Test // 테스트 메서드
// 각 테스트를 실행할때 마다 테스트를 위한 실행 객체를 만들고 테스트가 종료되면 실행 객체 삭제

public void junitTest(){
int a = 1;
int b = 2;
int sum = 3;

Assertions.assertEquals(sum, a + b); // 값이 같은지 확인  
}

JUnit 어노테이션

테스트는 어노테이션에 따라서 실행 순서가 정해진다

import org.junit.jupiter.api.*;  

public class JUnitCycleTest {  
    // 전체 테스트를 시작하기 전에 1회 실행하므로 메서드는 static 선언
    @BeforeAll  
    static void beforeAll() {  
        System.out.println("@BeforeAll");  
    }  

    // 테스트 케이스를 시작하기 전마다 실행
    @BeforeEach  
    public void beforeEach() {  
        System.out.println("@BeforeEach");  
    }  

    @Test  
    public void test1() {  
        System.out.println("test1");  
    }  

    @Test  
    public void test2() {  
        System.out.println("test2");  
    }  

    @Test  
    public void test3() {  
        System.out.println("test3");  
    }  

    // 전체 테스트를 마치고 종료하기 전에 1회 실행하므로 메서드는 static으로 선언
    @AfterAll  
    static void afterAll() {  
        System.out.println("@AfterAll");  
    }  

    // 테스트 케이스를 종료하기 전마다 실행
    @AfterEach  
    public void afterEach() {  
        System.out.println("@AfterEach");  
    }  

}

@BeforeAll

전체 테스트를 시작하기 전에 처음으로 한 번만 실행 예를 들어 데이터베이스를 연결해야 하거나 테스트 환경 조성

이 어노테이션은 전체 테스트 실행 주기에서 한번만 실행되기 때문에 static 선언

@BeforeEach

테스트 케이스를 시작하기 전에 매번 실행. 객체를 초기화 하거나 테스트에 필요한 값을 미리 넣을때 사용함

@AfterAll

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

@AfterEach

각 테스트를 종료하기 전에 매번 실행. 특정 테스트 이후에 특정 데이터를 삭제해야하는 경우 사용

JUnit과 사용하기 좋은 AssertJ

Assert J??

JUnit과 함께 사용해 검증문의 가독성을 높여주는 라이브러리

앞서 작성한 테스트 코드의 Assertion은 기댓값과 실제 비교값을 명시하지 않으므로 비교대상이 헷갈림!

Assertions.assertEquals(sum, a+b) // 가독성 나쁨

assertThat(a+b).isEqualTo(sum) // 가독성 좋음!

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

package com.rowoon.studyBoot;  

import org.junit.jupiter.api.AfterEach;  
import org.junit.jupiter.api.BeforeEach;  
import org.junit.jupiter.api.DisplayName;  
import org.junit.jupiter.api.Test;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;  
import org.springframework.boot.test.context.SpringBootTest;  
import org.springframework.http.MediaType;  
import org.springframework.test.web.servlet.MockMvc;  
import org.springframework.test.web.servlet.ResultActions;  
import org.springframework.test.web.servlet.setup.MockMvcBuilders;  
import org.springframework.web.context.WebApplicationContext;  

import static org.junit.jupiter.api.Assertions.*;  
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;  
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;  
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;  

@SpringBootTest  
@AutoConfigureMockMvc  
class TestControllerTest {  

    // 서버의 배포 없이 테스트용 MVC 환경을 만들어 요청 및 전송 응답 기능을 제공  
    // 즉, 컨트롤러를 테스트할때 사용하는 클래스  
    @Autowired  
    protected MockMvc mockMvc;  

    @Autowired  
    private WebApplicationContext context;  

    @Autowired  
    private MemberRepository memberRepository;  

    @BeforeEach  
    public void setMockMvc() {  
        this.mockMvc = MockMvcBuilders.webAppContextSetup(context).build();  
    }  

    @AfterEach  
    public void cleanUp() {  
        memberRepository.deleteAll();  
        ;    }  

    @DisplayName("getAllMembers: 아티클 조회에 성공한다.")  
    @Test  
    public void getAllMembers() throws Exception {  
        // given  
        // 원하는 api 주소  
        final String url = "/test";  
        // 멤버 객체 저장  
        Member savedMember = memberRepository.save(new Member(1L, "홍길동"));  

        // when  
        // perform() : 요청을 전송하는 역할을 하는 메서드 url 변수에 저장된 api 주소로 요청을 전송한다  
        // .accept() : 요청을 보낼때 무슨 타입으로 받을지 설정  
        final ResultActions result = mockMvc.perform(get(url) // 1  
                .accept(MediaType.APPLICATION_JSON)); // 2  

        // then 
	      // 응답코드가 isOK() => 200번대인지 확인  
				result
	      .andExpect(status().isOk())  
	      // 0번째 index의 id와 name 값을 가져오고 값이 같은지 확인한다  
	      .andExpect(jsonPath("$[0].id").value(savedMember.getId()))  
	      .andExpect(jsonPath("$[0].name").value(savedMember.getName()));  
    }  
}

HTTP 주요 응답 코드 정리

코드 매핑 메서드

200 OK isOk()
201 Create isCreated()
400 Bad Request isBadRequest()
403 Forbidden isForbidden()
404 Not Found isNotFound()
400번대 응답 코드 is4xxClientError()
500 Internal Server Error isInternalServerError()
500번대 응답 코드 is5xxServerError

 

반응형