Spring-boot x JUnit

27522 단어 JavajunitSpringJava

1. JUnit이란

  • Java의 단위 테스트 도구 및 테스트 프레임워크이다.
  • 함수별로 테스트가 가능하며, 개발자는 문서뿐만이 아니라 Test class 자체를 남겨 Class에 대한 history를 인수인계 할 수 있다.

1-1. TDD (Test Driven Development)

  • 테스트 주도 개발 : 테스트가 개발을 이끌어 나간다.

  • 함수 작성 시 종료 조건을 먼저 설계한 후에 코드를 작성한다라고 생각하면 된다.

  • TDD 개발 주기

    • RED : 항상 실패하는 테스트를 먼저 작성
    • GREEN : 테스트에 통과하는 프로덕션 코드 작성
    • REFACTOR : 테스트가 통과하면 프로덕션 코드에 대해서 중복 코드 제거 및 리팩토링

1-1-1. TDD가 왜 필요한가?

  • 일반적인 개발 주기

    • 일반적인 개발 주기는 요구사항 분석 -> 설계 -> 개발 -> 테스트 -> 배포를 따른다.
      이때 문제가 되는 사항은 요구사항은 언제나 명확하지 않다. 따라서 설계는 처음부터 완벽할 수 없다. 그렇기에 테스트 후 새로 코드를 짜야 하며, 요구사항들이 겹겹이 코드에 쌓이기 때문에 코드 재사용성은 떨어지고 품질 또한 떨어진다.

    • 작은 코드를 삽입해도, 전체 시스템을 테스트 해야 하기 때문에 테스트 비용이 점점 커진다.

  • TDD 개발 주기

    • 테스트 코드를 미리 작성한 후에 코드를 개발한다는 점에서 일반적인 개발 방식과 방식과 큰 차이가 있다. 디자인 단계에서 프로그램의 목적을 미리 정의해야하며, 무엇에 대해서 테스트를 할 지 미리 정의 (테스트 케이스) 해야만 한다.
    • 테스트 코드 작성중에 나타나는 버그들에 대해서는 테스트 케이스에 추가하며, 설계를 개선한다. 이러한 일련의 과정을 반복해 코드의 버그가 줄어들고 소스코드는 간결해진다.
    • 이러한 TDD 방식에도 단점이 존재하는데, 바로 생산성이 저하된다는것이다. 이러한 점을 개선하고자 노력해야한다.
  • TDD에서 가장 유명한 툴이 바로 Junit 이다.

1-2. Controller 테스트 코드 작성

Controller 작성

  1. 작성하기 전에 Test Controller를 작성해보자.

    package com.test.blog.test.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /*
    RestController 컨트롤러에서 반횐되는 값을 JSON 형식으로 변경해준다.
     */
    @RestController
    public class TestController {
        @GetMapping("/")
        public String test(){
            return "test";
        }
    }
    
    • @RestController: 컨트롤러에서 반환되는 값을 JSON 형식으로 변환해준다. 또한 @ResponseBody를 각 메소드마다 선언했던 것을 한번에 사용할 수 있게 해준다.
    • @GetMapping: HTTP Method인 Get인 요청을 받을 수 있는 API를 만들어 준다. (예전에는 @RequestMapping(method = RequestMethod.GET))
    • 위와 같이 작성한 후 서버를 실행시켜 localhost:8080 으로 접속하면 아래와 같이 표기된다.

테스트 코드 작성

  1. 클래스 우클릭 후 Go To > Test 를 클릭

  2. 사용하고자 하는 Junit 버전과 테스트 클래스 이름, 테스트 하고자 하는 함수를 설정 후 OK 버튼을 두르면 Test 코드 템플릿이 자동으로 만들어진다.

  3. 테스트 코드 작성

    package com.test.blog.test.controller;
    
    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.result.MockMvcResultMatchers.content;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
    
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
    
    
    @RunWith(SpringRunner.class) // SpringRunner class의 생성자 실행
    @WebMvcTest(controllers = TestController.class) // Web MVC에 집중할 수 있는어노테이션
    public class TestControllerTest {
    
        @Autowired
        private MockMvc mvc;
    
        @Test
        public void test1() throws Exception{
            final String test = "test";
            mvc.perform(get("/"))
                    .andExpect(status().isOk())
                    .andExpect(content().string(test));
        }
    }
    • @RunWIth(Class): 타 클래스의 생성자를 실행할 수 있는 어노테이션
      • 여기서는 SpringRunner라는 스프링 실행자를 사용
      • 즉, 스프링 부트 테스트와 JUnit 사이에 연결자 역할
    • @WebMvcTest
      • 여러 스프링 테스트 어노테이션 중, Web(Spring MVC)에 집중할 수 있는 어노테이션
      • 선언할 경우 @Controller, @ControllerAdvice 등을 사용 가능
      • 단, @Service, @Component, @Repository 등은 사용할 수 없다
      • 여기서는 컨트롤러만 사용한다
    • private MockMvc mvc
      • 웹 API를 테스트할 때 사용
      • 스프링 MVC 테스트의 시작점
      • 이 클래스를 통해 HTTP GET,POST 등에 대한 API 테스트를 할 수 있다
    • mvc.perform(get("/hello"))
      • MockMvc를 통해 /hello 주소로 HTTP GET 요청을 한다
      • 체이닝이 지원되어 아래와 같이 여러 검증 기능을 이어서 선언할 수 있다
    • .andExpect(status().isOk())
      • mvc.perform의 결과를 검증
      • HTTP Header의 Status를 검증
      • 우리가 흔히 알고 있는 200,404,500 등의 상태를 검증한다
    • .andExpect(content().string(hello))
      • mvc.perform의 결과를 검증한다
      • 응답 본문의 내용을 검증한다

1-3. Lombok 설치

  1. build.gradle > dependencies 에 다음을 추가

    compileOnly 'org.projectlombok:lombok'
     annotationProcessor 'org.projectlombok:lombok'
  2. Intellj lombok 플러그인 추가

    1. Intellj > File > Settings... > Plugins 클릭
    2. Lombok을 검색해 install
    3. 같은 창에서 좌측의 Build, Execution, Deployment > Compiler > Annotation Processors 클릭 후 Enable annotation processing체크

1-3-1. Lombok x DTO 테스트

TestDTO 클래스 작성

package com.test.blog.test.dto;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public class TestDTO {
    private final String value;
    private final int id;
}
  • @Getter : 필드의 getter 메소드를 자동으로 만들어줌
  • @RequiredArgsConstructor : final 키워드가 붙은 상수형 필드 변수들에 대해서 생성자를 만들어줌. final 키워드가 없는 필드는 생성자에 포함되지 않음.
  • DTO (Data Transfer Object) : 데이터를 담은 자바 빈즈
    • VO (Value Object): DTO와 동일하지만 read-only
    • Entity : DB Table과 1 : 1 로 매칭이 되는 class. DB 테이블에 존재하는 컬럼만 필드로 가져야한다.

Test Code 작성

package com.test.blog.test.dto;

import static org.assertj.core.api.Assertions.*;
import org.junit.Test;



public class TestDTOTest {
    @Test
    public void DTO_X_LombokTest(){
        String value = "test";
        int id = 0;

        TestDTO dto = new TestDTO(value, id);

        assertThat(dto.getId()).isEqualTo(id);
        assertThat(dto.getValue()).isEqualTo(value);
    }
}   
  • assertThat : asserj라는 테스트 검증 라이브러리 검증 메소드
  • isEqualTo : 검증하고자하는 대상을 메소드 인자로 받는다. 메소드 체이닝이 지원돼 isEqualTo와 같이 메소드를 이어서 쓸 수 있다.

1-3-2. Test controller X DTO X 테스트 코드 작성

1. TestController 작성

package com.test.blog.test.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.test.blog.test.dto.TestDTO;
/*
RestController 컨트롤러에서 반횐되는 값을 JSON 형식으로 변경해준다.
 */
@RestController
public class TestController {
    @GetMapping("/")
    public String test(){
        return "test";
    }
    @GetMapping("/test")
    public TestDTO setTestDTO(@RequestParam("value") String value,
                             @RequestParam("id") int id ){
        return new TestDTO(value, id);
    }
}
  - @RequestParam: url 주소로 값을 받아올 수 있음. 위와 같은 코드 일 때, `http://localhost:8080/test?value=TEST&id=1` 로 값을 전송할 수 있음.
  

2. TestCode 작성

    @Test
  public void testDTO() throws Exception {
      final String value = "TEST";
      final int id = 0;
      mvc.perform(get("/test").param("value", value).param("id", String.valueOf(id)))
              .andExpect(status().isOk())
              .andExpect(jsonPath("$.value", CoreMatchers.is(value))) // $를 기준으로 필드명 명시
              .andExpect(jsonPath("$.id", CoreMatchers.is(id)));
  }
 - param : http get방식에서 전달될수 있는 요청 파라미터의 값을 삽입. String 데이터만 허용. 
 - jsonPath : JSON 형태의 값을 검증. $을 기준으로 필드명을 명시할 수 있음.
 

좋은 웹페이지 즐겨찾기