[SpringBoot & AWS] 2. 스프링 부트에서 테스트 코드 작성

redcarrot01·2021년 5월 11일
0

SPRINGBOOT

목록 보기
2/8
post-thumbnail

까먹지 말것

ctrl + shift + a : 플러그인 action 검색
alt + enter : 자동 import

2.1 테스트 코드 소개


TDD와 단위테스트(Unit test)는 다른 것!

TDD(Test Driven Development)

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

테스트 코드를 먼저 작성하고 테스트를 통과하기 위한 로직을 작성하는 것

프로그램에 대한 요구사항을 반영하여 제대로 동작하는지 피드백 받는 하나의 프로그램

RED : 항상 실패하는 테스트 먼저 작성
GREEN : 테스트가 통과하는 프로덕션 코드 작성
REFACTOR : 테스트가 통과하면 프로덕션 코드 리팩토링

단위 테스트

TDD의 첫 번째 단계인 기능 단위의 테스트 코드 작성

순수하게 테스트 코드를 작성

왜 단위 테스트 코드를 작성하는가?

  • 개발 단계 초기에 문제 발견 가능
  • 코드 리팩토링하거나 라이브러리 업그레이드 등에서 기존 기능이 올바르게 작동하는지 확인 가능
  • 기능에 대한 불확실성 감소
  • 시스템에 대한 실제 문서 제공. 단위테스트 자체가 문서로 사용됨
  1. 빠른 피드백 -> 수정할때마다 톰캣 서버를 실행하는 일을 할 필요가 없어짐
  2. 단위테스트를 실행만 하면 자동검증이 가능
  3. 새로운 기능이 추가되었을 때, 기존 기능 동작을 보장해줌

자바에서는 Junit -> 테스트 프레임 워크

아래는** Junit4** 사용하여 작성했습니다.

2.2 Hello Controller 테스트 코드 작성


0. [참고] 아래 생성할 전체 파일 위치

1. 패키지명은 com.yujin.service.springboot로 작성

(보통 패키지명은 웹사이트 주소 역순)

2. 패키지 아래에 Application 클래스 생성

package com.yujin.service.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
    public static void main(String[] args){
        SpringApplication.run(Application.class, args);
    }
}

Application 클래스 - 메인 클래스

  • @SpringBootApplication : 스프링 부트의 자동 설정, 스프링 Bean 읽기와 생성을 모두 자동 설정

    • 프로젝트 최상단에 위치(그 이유는 @SpringBootApplication이 있는 위치부터 설정을 읽어들이기 때문)
  • SpringApplication.run : 내장 WAS(Web Application Server)를 실행

    • 내장 WAS란 애플리케이션 내부에서 WAS 실행하는 것
    • 톰캣 설치 X, 스프링부트로 만들어진 Jar 파일로 실행
    • 스프링 부트에서는 내장 WAS 권장 - 언제 어디서나 같은 환경에서 배포 가능
    • 외장 WAS의 경우, 모든 서버는 WAS의 종류, 버전, 설정 다 일치시켜야 함

3. HelloController 클래스 생성

com.yujin.service.springboot.web에 HelloController api 생성

package com.yujin.service.springboot.web;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController // 1
public class HelloController {

    @GetMapping("/hello") // 2
    public String hello(){
        return "hello";
    }
}
  1. **@RestController **
    • 컨트롤러를 JSON을 반환하는 컨트롤러로 만들어 줌
  2. @GetMapping
    • HTTP Method인 Get인 요청을 받을 수 있는 API 생성
    • /hello 요청 오면 문자열 hello 반환 기능

4. 테스트 코드로 검증, WAS NO!

**src/test/java에 앞에서 생성했던 패키지 그대로 다시 생성 **

5. HelloControllerTest 클래스 생성

package com.yujin.service.springboot.web;

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.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@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. @RunWith(SpringRunner.class)
    • JUnit 실행자 외에 다른 실행자인 SpringRunner 사용
    • 스프링 부트 테스트와 JUnit 사이에 연결자 역할
      2.** @WebMvcTest**
    • Web(Spring MVC)에 집중할 수 있는 어노테이션
    • 선언할 경우 @Controller, @ControllerAdvice 등을 사용
    • 단, @Service, @Component, @Repository 등은 사용불가
    • 여기서는 컨트롤러만 사용
  2. @Autowired
    • 스프링이 관리하는 빈(Bean)을 주입 받기
    • 빈(Bean): ApplicationContext가 만들어서 그 안에 담고있는 객체
  3. private MockMvc mvc
    • 웹 API를 테스트할 때 사용
    • 스프링 MVC 테스트의 시작점
    • 이 클래스를 통해 HTTP GET,POST 등에 대한 API 테스트 가능
  4. mvc.perform(get("/hello"))
    • MockMvc를 통해 /hello 주소로 HTTP GET 요청
    • 체이닝이 지원되어 아래와 같이 여러 검증 기능을 이어서 선언
    • 체이닝 : 한 객체에 다양한 메서드 사용
  5. .andExpect(status().isOk())
    • HTTP Header의 Status를 검증 (200, 404, 500)
  6. .andExpect(content().string(hello))
    • 응답 본문의 내용을 검증(여기서는 hello가 맞는지)

6. 테스트 코드 실행

public void hello가_리턴된다() throws Exception 이부분의 화살표 run

status().isOk(), content().string(hello) 검증 성공

7. Application에서 실행 확인

결론 : 테스트 코드로 먼저 검증 후, 믿음이 안가면 프로젝트 main에서 실행 확인

2.3 롬북 소개


롬북(lombok) : Getter, Setter, 기본 생성자, toString 등 어노테이션 자동 생성해주는 라이브러리

롬북을 설치하고 IDE 재실행해야 함

2.4 HelloController 코드를 롬북으로 전환


롬북으로 변경하고, 테스트 코드를 통해 문제가 생기는지 알아보기

1. main/java...web패키지에 dto 패키지 추가

모든 응답 Dto는 이 Dto패키지 내 추가

2. HelloResponseDto 작성

main/java...web/dto/HelloResponseDto

package com.yujin.service.springboot.web.dto;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter //1
@RequiredArgsConstructor //2
public class HelloResponseDto {
    private final String name;
    private final int amount;
}
  1. @Getter
    • 선언된 모든 필드의 get 메소드를 생성
  2. @RequiredArgsConstructor
    • 선언된 모든 final 필드가 포함된 생성자를 생성
    • final이 없는 필드는 생성자에 포함되지 않음

3. HelloResponseDtoTest 클래스 작성

이 Dto에 적용된 롬복 잘 작동하는지 알아보기 위함

package com.yujin.service.springboot.web.dto;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
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, 2
        assertThat(dto.getAmount()).isEqualTo(amount);
    }
}
  1. assertThat
    • assertj라는 테스트 검증 라이브러리의 검증 메소드
  2. isEqualTo
    • assertj의 동등 비교 메소드
    • assertThat에 있는 값과 isEqualTo의 값을 비교해서 값이 같을 때만 성공

4. 테스트 실행 결과

정상 수행 -> 롬북의 @Getter로 get 메서드가, @RequiredArgsConstructor로 생성자가 자동으로 생성되는 것이 증명

5. HelloController에도 새로 만든 ResponseDto를 사용하도록 코드 추가

HelloController 코드 추가

    // ResponseDto를 사용하는 코드
    @GetMapping("hello/dto")
    public HelloResponseDto helloDto(@RequestParam("name")
                                     String name, // 1
                                     @RequestParam("amount")
                                     int amount){
        return new HelloResponseDto(name, amount);
    }
  1. @RequestParam
    • 외부에서 API로 넘긴 파라미터를 가져오는 어노테이션

name, amount는 api를 호출하는 곳에서 넘겨준 값

HelloControllerTest 코드 추가

추가된 api 테스트하는 코드

        @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)));

        }
  1. param
    • API 테스트할 때 사용될 요청 파라미터를 설정
    • 단, 값은 String만 허용됩니다.
    • 숫자/날짜 등의 데이터도 작성할 때는 문자열로 변경해야한 가능
  2. jsonPath
    • JSON 응답값을 필드별로 검증할 수 있는 메소드
    • $를 기준으로 필드명을 명시
    • 여기서는 name, amount 검증

6. 테스트 코드 실행 확인

json이 리턴되는 api 역시 정상적으로 통과됨

관심 있을 만한 포스트

0개의 댓글