Super Kawaii Cute Cat Kaoani
본문 바로가기
⚙️ Back-end/SpringBoot

Springboot [4] : 테스트

by wonee1 2024. 3. 5.
728x90

* 책 스프링부트 3 백엔드 개발자 되기 자바편을 공부하면서 정리한 내용입니다
 
 

스프링부트 3와 테스트 

 
 
given-when-then 패턴 
 

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

 
JUnit: 자바 프로그래밍 언어용 단위 테스트 프레임워크
AssertJ: 검증문인 어설션을 작성하는 데 사용되는 라이브러리
Hamcrest: 표현식을 이해하기 쉽게 만드는 데 사용되는 Matcher 라이브러리 
 
 

JUnit이란?

 
☑️JUnit이란?
자바 언어를 위한 단위 테스트 프레임워크

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

 

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);// 값이 같은지 확인

    }
}

JUnitTest.java
 

  • @DisplayName 애너테이션은 테스트 이름을 명시
  • @Test 애너테이션을 붙인 메서드는 테스트를 수행하는 메서드
  • Junit은 테스트끼리 영향을 주지 않도록 각 테스트를 실행할 때마다 테스트를 위한 실행 객체를 만들고 테스트가 종료되면 실행객체를 삭제함

 

import org.aspectj.lang.annotation.After;
import org.junit.jupiter.api.*;

public class JUnitCycleTest {
    @BeforeAll//전체 테스트를 시작하기 전에 1회 실행하므로 메서드는 static으로 선언
    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");

    }

    @AfterAll
    static void afterAll(){
        System.out.println("@AfterAll");
    }

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

}

 
 
@BeforeAll 애너테이션

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

 
@BeforeEach 애너테이션 

  • 테스트 케이스를 시작하기 전에 매번 실행
  • 테스트 메서드에서 사용하는 개게를 초기화하거나 테스트에 필요한 값을 미리 넣을 때 사용
  • 각 인스턴스에 대해 메서드를 호출해야 하므로 메서드 static이 아니어야함

 
@AfterAll 애너테이션 
 

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

@AfterEach 애너테이션
 

  • 각 테스트 케이스를 종료하기 전 매번 실행
  • 테스트 이후에 특정 데이터를 삭제해야 하는 경우 사용
  • 메서드를 static이 아니어야

 
☑️결과 
 

  • @BeforeAll  애너테이션으로 설정한 메서드 실행되고, 그 이후에는 테스트 케이스 개수 만큼
  • @BeforeEach->@Test ->@AfterEach의 생명주기로 테서트가 진행됨.
  • 모든 테스트 케이스가 끝나면 @AfterAll 애너테이션으로 설정한 메서드를 실행하고 종료 
AssertJ로 검증문 가독성 높이기 

 
 
☑️AssertJ이란?
 JUnit 과 함깨 사용해 검증문의 가독성을 확 높여주는 라이브러리
 
 

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

 
가독성이 좋은 AssertJ예시
 
 

테스트 코드 작성

 
 
 
@Autowired 
의존 객체의 타입에 해당하는 빈을 찾아 주입하는 역할을 함
*빈은 스프링 컨테이너에 의해 관리되는 재사용 가능한 소프트웨어 컴포넌트
 

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.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 // MockMvc 생성 및 자동 구성 
class TestControllerTest {

    @Autowired
    protected MockMvc mockMvc;

    @Autowired
    private WebApplicationContext context;

    @Autowired
    private MemberRepository memberRepository;

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

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

    @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 perform 메서드는 요청을 전송하는 역할,ResultActions 객체를 받음
                .accept(MediaType.APPLICATION_JSON)); // 2 accept 메서드는 요청을 보낼 때 무슨 타입으로 응답을 받을 지 결정하는 메서드

        // then
        result
                .andExpect(status().isOk()) //3 andExpect 메서드는 응답을 검증
                .andExpect(jsonPath("$[0].id").value(savedMember.getId())) //4 jsonPath는 JSON 응답값의 값을 가져오는 역할을하는 메서드 
                .andExpect(jsonPath("$[0].name").value(savedMember.getName()));
    }
}

TestControllerTest.java
 
 
Given: 멤버를 저장When: 멤버 리스트를 조회하는 api 추출Then : 응답 코드가 200 OK이고, 반환받은 값 중에 0번째 요소의 id와 name이 저장된 값과 같은지 확인
 
 

 

728x90