ysm7663 2021. 8. 25. 17:15
728x90

■ TDD란?

TDD (Test Driven Development) : 테스트 주도 개발

특징

  • 테스트가 주도하는 개발
  • 테스트 코드를 먼저 작성

레드 그린 사이클

ㅁ Red : 항상 실패하는 테스트를 먼저 작성

ㅁ Green : 테스트가 통과하는 프로덕션 코드를 작성

ㅁ REFACTORY : 테스트가 통과하면 프로덕션 코드를 리팩토링

 

■ 단위 테스트를 해야하는 이유

  • 개발단계 초기에 문제를 발견하게 도와준다 (빠른 피드백 가능)
  • 개발자가 나중에 코드를 리팩토링하거나 라이브러리 업그레이드 등에서 기존 기능이 올바르게 작동하는지 확인 가능하다(회기 테스트)
  • 기능에 대한 불확실성을 감소시킬 수 있다
  • 시스템에 대한 실제 문서를 제공한다 (단위 테스트 자체가 문서로 사용할 수 있디)

 

■ TDD vs 단위 테스트

  TDD 단위테스트
순서 테스트 먼저 상관 없음
리펙토링 여부 O X
중점 테스트 중점 기능 중점

 

■ 테스트 프레임워크

xUnit : 개발환경에 따라 Unit 테스틑 도와주는 도구

종류

  • JUnit - Java
  • DBUnit - DB
  • CppUnit - C++
  • NUnit - .net

 

■ HelloController 테스트 클래스 생성

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringRunner.class) // 1
@WebMvcTest(controllers = HelloController.class) // 2

public class HelloControllerTest {

    @Autowired // 3
    private MockMvc mvc; // 4

    @Test
    public void hello가_리턴된다() throws Exception {
        String hello = "hello";

        mvc.perform(get("/hello"))	// 5
                .andExpect(status().isOk())	//6
                .andExpect(content().string(hello)); // 7
    }
}

 

  1. JUnit에 내장된 실행자 외의 다른 실행자를 실행 >> SpringRunner
  2. Web에 집중시키는 Annotation
    1. JPA 기능이 작동하지 않음
    2. @Controller, @ControllerAdvice 사용 가능
    3. @Service, @Component, @Repository 사용 불가능 
  3. 스프링이 관리하는 Bean을 주입 받음
  4. 웹 API를 테스트 할 때 사용, 스프링 MVC 테스트의 시작점
    1. HTTP GET, POST 등에 대한 API 테스트를 할 수 있음
  5. MockMvc를 통해 /hello 주소로 HTTP GET 요청
    1. 체이닝이 지원되어 아래와 같이 여러 검증 기능을 이어서 선언할 수 있다
  6. mvc.perform의 결과를 검증, HTTP Header의 Status를 점증
    1. 200, 404, 500 등의 상태를 검증 
    2. status.isOk() >> 200 인지 아닌지 검증
  7. mvc.perform의 결과를 검증, 응답 본문의 내용을 검증

 

■ HelloResponseDto 테스트 클래스 생성

import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat; // 3

public class HelloResponseDtoTest {

    @Test
    public void 롬복_기능_테스트() {
        // given
        String name = "test";
        int amount = 1000;

        // when
        HelloResponseDto dto = new HelloResponseDto(name, amount);

        // then
        assertThat(dto.getName()).isEqualTo(name); // 1
        assertThat(dto.getAmount()).isEqualTo(amount); // 2
    }
}

 

  1. assertThat 
    1. assertj라는 테스트 검증 라이브러리의 검증 메소드
    2. 검증하고 싶은 대상을 메소드 인자로 받음
    3. 메소드 체이닝이 지원되어 isEqualTo와 같이 메소드를 이어서 사용할 수 있음
  2. isEqualTo
    1. assertj의 동등 비교 메소드
    2. assertThat에 있는 값과 isEqualTo의 값을 비교해서 같을 때만 성공
  3. Junit의 assertThat이 아닌 assertj 의 assertThat 사용 이유
    1. CoreMatchers와 달리 추가적으로 라이브러리가 필요하지 않음
    2. 자동완성이 좀 더 확실하게 지원됨

 

* Given - When - Then Pattern??

: 어느 정도 실력이 있는 개발자라면 굳이 사용하지 않아도 되지만, 주니어 개발자 혹은 테스트 코드를 처음 작성하는 개발자는 테스트 코드 작성 실력 향상에 도움이 될 수 있다.

 

[준비 - 실행 - 검증]

준비 : 테스트를 위해 준비하는 과정

  • 테스트에 사용하는 변수, 입력 값 등을 정의
  • Mock 객체를 정의

실행 : 실제로 테스트를 실행하는 과정

 

검증 : 테스트를 검증

   - 예상한 값, 실제 실행을 통해 나온 값을 비교, 검증

 

■ API를 테스트 하는 HelloController 테스트 클래스 생성

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonpath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = HelloController.class)

public class HelloControllerTest {

    @Autowired
    private MockMvc mvc;

    @Test
    public void hello가_리턴된다() throws Exception {
        String hello = "hello";

        mvc.perform(get("/hello"))
                .andExpect(status().isOk())
                .andExpect(content().string(hello));
    }
    
    @Test
    public void helloDto가_리턴된다() throws  Exception {
        String name = "hello";
        int amount = 1000;

        mvc.perform(
                get("/hello/dto")
                        .param("name", name)	// 1
                        .param("amount", String.valueOf(amount)))
                            .andExpect(status().isOk())
                            .andExpect(jsonPath("$.name", is(name)))	// 2
                            .andExpect(jsonPath("$.amount", is(amount)));
    }
    
    
}

 

*  JSON이 리턴되는 API 역시 정상적으로 테스트가 통과하는 것을 확인 할 수 있다.

 

  1. API를 사용할 때 사용될 요청 파라미터를 설정 (값은 String만 허용, 숫자 등은 문자열로 변경해서 사용)
  2. JSON 응답값을 필드별로 검증할 수 있는 메소드
    1. $를 기준으로 필드명을 명시

 

* API(Application Programming Interface)란?

: 응용 프로그래밍에서 사용할 수 있도록 운영체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스

728x90