테스트 코드를 왜 작성할까?

1. 빠른 피드백 ( 계속 톰캣을 내렸다가 다시 실행하지 않아도 됨).

2. 눈으로 검증하는 테스트 코드를 자동 검증하게 할 수 있음.

3. 개발자가 만든 기능을 안전하게 보호해 줌

 

TDD단위 테스트는 다른 것이다.

 

- 항상 실패하는 테스트를 먼저 작성하고 (Red)

- 테스트가 통과하는 프로덕션 코드를 작성하고 (Green)

- 테스트가 통과하면 프로덕션 코드를 리팩터링 합니다 (Refactor)

 

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

 

테스트 코드 작성을 도와주는 프레임 워크

가장 대중적인 테스트 프레임워크 xUnit

 

  • Junit - Java
  • DBUnit - DB
  • CppUnit - C++
  • NUnit -. net
package com.goodee.cando;

import javafx.application.Application;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

Application 클래스는 앞으로 프로젝트의 메인 클래스

@SpringBootApplication으로 인해 스프링 부트의 자동 설정, 스프링 Bean 읽기와 생성을 모두 자동으로 함.

@SpringBootApplication위치부터 읽어서 맨 상단에 위치해야 함

 

내장 was를 서버를 내부에서 실행시키는 것

 

컨트롤러와 관련된 클래스들은 모두 web에 담을 것.

Run tests using 부분 gradle에서 변경 시킨 것

그래도 에러가 났는데 문법이 많이 바뀌었기 때문

https://jojoldu.tistory.com/539

 

(2020.12.16) 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 최신 코드로 변경하기

작년 11월 말에 스프링 부트와 AWS로 혼자 구현하는 웹 서비스를 출판 하였습니다. Spring Boot가 2.1 -> 2.4로, IntelliJ IDEA가 2019 -> 2020으로 오면서 너무 많은 변화가 있다보니, 집필할 때와 비교해 실습

jojoldu.tistory.com

바뀐 문법 여기서 확인 가능

 

package com.goodee.cando;

import com.goodee.cando.web.HelloController;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
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;

@ExtendWith(SpringExtension.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"))  // 5
                .andExpect(status().isOk())  // 6
                .andExpect(content().string(hello));  // 7

    }
}

@ExtendWith(SpringExtension.class)

- 테스트를 진행할 때 JUnit에 내장된 실행자 외에 다른 실행자를 실행시킴

- SpringExtension 스프링 실행자를 사용

- 즉, 스프링 부트 테스트와 JUnit 사이에 연결자 역할을 함

 

@WebMvcTest

- 여러 스프링 어노테이션 중, Web(Spring MVC)에 집중할 수 있는 어노테이션

- 선언할 경우 @Controller, @ControllerAdvice 등을 사용할 수 있음

- 단 @Service, @Component, @Repository는 사용할 수 없음

- 여기서는 컨트롤러만 사용하기 때문에 선언함

 

@Autowired

- 스프링이 관리하는 빈(Bean)을 주입 받음.

 

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 등의 상태를 검증

- 여기선 OK 즉, 200인지 아닌지를 검증함

 

. andExpect(content(). string(hello))

- mvc.perform의 결과를 검증함

- 응답 본문의 내용을 검증함

- Controller에서 "hello"를 리턴하기 때문에 이 값이 맞는지 검증

 

경로가 잘못돼서 에러가 났었음.


롬복(lombok) 설치

롬북은 Getter, Setter, 기본 생성자, toString 등을 어노테이션으로 자동 생성해 준다.

build.gradle에 추가시킴.

 이클립스의 경우엔 롬복 설치가 번거롭지만, 인텔리제이에선 플러그인 덕분에 쉽게 설정이 가능.

 

 프로젝트에 롬복을 추가해 보겠음.

 

기존 코드를 롬복으로 변경해 보겠음.

 

web 패키지에 dto 패키지를 추가하겠음

앞으로 모든 응답 Dto는 Dto 패키지에 추가한다.


package com.goodee.cando.web.dto;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public class HelloResponseDto {

    private final String name;
    private final int amount;
}

@Getter

- 선언된 모든 필드의 get 메서드를 생성해 줍니다.

@RequiredArgsConstructor

- 선언된 모든 final 필드가 포함된 생성자를 생성해 줍니다.

- final이 없는 필드는 생성자에 포함되지 않습니다.

package com.goodee.cando.web.dto;

import org.junit.jupiter.api.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);
        assertThat(dto.getAmount()).isEqualTo(amount);
    }
}

assertThat

- assertj라는 테스트 검증 라이브러리의 검증 메서드입니다.

- 검증하고 싶은 대상을 메서드 인자로 받습니다.

- 메소드 체이닝이 지원되어 isEqualTo와 같이 메서드를 이어서 사용할 수 있습니다.

isEqualTo

- assertj의 동등 비교 메서드입니다.

- assertThat에 있는 값과 isEqualTo의 값을 비교해서 같을 때만 성공입니다.

 

Junit의 기본 asserThat이 아닌 assertj의 asserThat을 사용했습니다.

import문을 보면 알 수 있음.

assertj 역시 Junit에서 자동으로 라이브러리 등록을 해준다.

 

장점은 뭐가 있을까?

 

- CoreMatchers와 달리 추가적으로 라이브러리가 필요하지 않습니다.

  - Junit의 assertThat을 쓰게 되면 is()와 같이 CoreMatchers 라이브러리가 필요합니다.

 

- 자동완성이 좀 더 확실하게 지원됩니다.

 - IDE에서는 CoreMatchers와 같은 Matcher 라이브러리의 자동완성 지원이 약합니다.

 

@RequestParam

- 외부에서 API로 넘긴 파라미터를 가져오는 어노테이션입니다.

- 여기서는 외부에서 name (@Request("name")) 이란 이름으로 넘긴 파라미터를 메서드 파라미터 name(String name)에 저장하게 됩니다.

 

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

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

param

- API 테스트할 때 사용될 요청 파라미터를 설정합니다.

- 단, 값은 String만 허용됩니다.

- 그래서 숫자/날짜 등의 데이터도 등록할 때 문자열로 변경해야만 가능합니다.

 

jsonPath

- JSON 응답 값을 필드별로 검증할 수 있는 메서드입니다.

- $를 기준으로 필드명을 명시합니다.

- 여기서는 name과 amount를 검증하니 $. name, $. amount로 검증합니다.

 

 

+ Recent posts