[Spring] 테스트 코드

개발log·2024년 4월 18일

Spring

목록 보기
14/16
post-thumbnail

테스트 코드

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

테스트 코드의 패턴 - given-when-then

  1. given - 테스트 실행을 준비하는 단계
  2. when - 테스트를 진행하는 단계
  3. then - 테스트 결과를 검증하는 단계
@DisplayName("새로운 메뉴를 저장")
@Test
public void saveMenuTest(){
	//given : 메뉴를 저장하기 위한 준비 과정
    final String name = "아메리카노";
    final int price = 2000;
    
    final Menu americano = new Menu(name, price);
    
    //when : 실제로 메뉴를 저장
    final long saveId = menuService.save(americano);
    
    //then : 메뉴가 잘 추가되었는지 검증
    final Menu saveMenu = menuService.findById(saveId).get();
    assertThat(saveMenu.getName()).isEqualTo(name);
    assertThat(saveMenu.getPrice()).isEqualTo(price);

테스트 도구

spring-boot-starter-test 스타터에 테스트를 위한 도구가 모여있음.

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

JUnit

자바 언어를 위한 단위 테스트 프레임워크
※ 단위 테스트 : 작성한 코드가 의도대로 작동하는지 작은 단위로 검증하는 것

JUnit의 특징

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

JUnit의 성공 단위 테스트 코드

    @DisplayName("1 + 2는 3이다")
    @Test
    public void junitTest() {
        int a = 1;
        int b = 2;
        int sum = 3;

        Assertions.assertEquals(a + b, sum);
    }

JUnit의 실패 단위 테스트 코드

    @DisplayName("1 + 3는 4이다")
    @Test
    public void junitFailedTest() {
        int a = 1;
        int b = 3;
        int sum = 3; // 원래 정답은 4이어야 함

        Assertions.assertEquals(a + b, sum);
    }

JUnit의 애너테이션

  • @BeforeAll : ( static ) 전체 테스트를 시작하기 전에 처음으로 한 번만 실행
    데이터베이스를 연결하거나 테스트 환경을 초기화 할 때 사용
  • BeforeEach : 테스트 케이스를 시작하기 전에 매번 실행
    테스트 메서드에서 사용하는 객체를 초기화하거나 테스트에 필요한 값을 미리 넣을 때 사용
  • AfterAll : ( static ) 전체 테스트를 마치고 종료하기 전에 한 번 실행
    데이터베이스 연결을 종료하거나 공통적으로 사용되는 자원을 해제할 때 사용
  • AfterEach : 각 테스트 케이스를 종료하기 전 매번 실행
    테스트 이후에 특정 데이터를 삭제해야하는 경우 사용
    @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("test1");
    }

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

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

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


AssertJ

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

기댓갑과 비교값이 잘 구분되지 않는 Assertion 예

Assertions.assertEquals(sum, a + b);

가독성이 좋은 AssertJ 예

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

자주 사용하는 메서드

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

테스트 코드

테스트 코드 준비

  • @SpringBootTest : @SpringBootApplication이 있는 클래스를 찾고 그 클래스에 포함되어 있는 빈을 찾은 다음에 테스트용 애플리케이션 컨텍스트 생성
  • AutoConfigureMockMvc : MockMvc를 자동 생성하고 자동으로 구성하는 애너테이션
    ※ MockMvc는 애플리케이션을 서버에 배포하지 않고도 테스트용 MVC 환경을 만들어 요청 및 전송, 응답 기능을 제공하는 유틸리티 클래스 - 컨트롤러 테스트 시 사용
  • BeforeEach : MockMvcSetUp() 메서드를 실행해 MockMvc를 설정
  • AfterEach : cleanUp() 메서드를 실행해 member 테이블에 있는 데이터들을 모두 삭제
@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();
    }
}

테스트 코드

  • Given : 멤버를 저장
  • When : 멤버 리스트를 조회하는 API 호출
  • Then : 응답 코드가 200 OK이고, 반환받은 값 중에 0번째 요소의 id와 name이 저장된 값과 같은지 확인
  • perform() : 요청 전송 - ResultActions 객체는 반환값을 검증하고 확인하는 andExcept() 메서드를 제공
  • accpet() : 요청을 보낼 때 무슨 타입으로 응답을 받을지 결정하는 메서드
  • andExcept() : 응답 검증 - 응답 코드가 200인지 확인
  • `jsonPath("[0].[0].{필드명}" : JSON의 응답값을 가져요는 역할 - 0번째 배열에 들어있는 객체의 id, name 값을 가져오고, 저장된 값과 같은지 확인
 
    @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())
                .andExpect(jsonPath("$[0].id").value(savedMember.getId())) // 3
                //4 응답의 0번째 값이 DB에 저장한 값과 같은지 확인
                .andExpect(jsonPath("$[0].name").value(savedMember.getName()));
    }
}

업로드중..

profile
나의 개발 저장소

0개의 댓글