1️⃣ TDD
"테스트 주도 개발: 테스트가 개발을 이끌어 나간다."
- RED : 항상 실패하는 테스트를 먼저 작성
- GREEN : 테스트에 통과하는 프로덕션 코드 작성
- REFACTOR : 테스트가 통과하면 프로덕션 코드를 리팩토링
테스트를 작성하고 그걸 통과하는 코드를 만드는 과정을 반복하며 제대로 동작하는지에 대한 피드백을 적극적으로 받는 것
💚 TDD를 사용하는 이유?
- 개발 단계 초기에 문제를 발견하게 해준다.
- 추후에 코드를 리팩토링하거나 라이브러리 업그레이드 등에서 기존기능이 올바르게 작동하는지 확인할 수 있다.
- 기능에 대한 불확실성을 감소시켜준다.
- 시스템에 대한 실제 문서를 제공한다. 즉, 단위 테스트 자체가 문서로 사용할 수 있다.
테스트 코드 작성시 사람의 눈으로 검증하지 않게 자동검증이 가능
작성된 단위 테스트를 실행만 하면 더는 수동검증이 필요 없음
cf. 단위 테스트는 TDD의 첫 번째 단계인 기능 단위의 테스트 코드를 작성하는것을 이야기함
2️⃣ Hello Controller 테스트 코드 작성하기
💚 Application Class 작성
Application 클래스는 앞으로 만들 프로젝트의 메인 클래스
package com.jojoldu.book.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);
}
}
📌 @SpringBootApplication
- 스프링 부트의 자동 설정, 스프링 Bean 읽기와 생성을 모두 자동으로 설정
- 이 코드가 있는 위치부터 설정을 읽어가기 때문에 항상 프로젝트 최상단에 위치할 것
📌 SpringApplication.run
- 내장 WAS(Web Application Server, 웹 어플리케이션 서버)를 실행
- 내장 WAS? 별도로 외부에 WAS를 두지 않고 애플리케이션이 실행할 때 내부에서 WAS를 실행하는 것
- -> 서버에 톰캣을 설치할 필요가 없어지고 스프링 부트로 만들어진 Jar 파일 (실행 가능한 Java 패키징 파일)로 실행하면 됨
💚 테스트 위한 Controller 만들기
package com.jojoldu.book.springboot.web;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "hello";
}
}
📌 @RestController
- 컨트롤러를 JSON을 반환하는 컨트롤러로 만들어 줌
- 예전에는 @ResponseBody를 각 메소드마다 선언했던 것을 한번에 사용할 수 있게 해준다.
📌 @GetMapping
- HTTP Method인 Get인 요청을 받을 수 있는 API를 만들어 준다.
- 예전에는 @RequestMapping(method = RequestMethod.GET)으로 사용되었음
💚 HelloControllerTest Class 작성
package com.jojoldu.book.springboot.web;
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.runner. RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
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)
@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));
}
}
📌 @RunWith(SpringRunner.class)
- 테스트를 진행할 때 JUint에 내장된 실행자 외에 다른 실행자를 실행시킵니다.
- 여기서는 SpringRunner라는 스프링 실행자를 사용합니다.
- 즉, 스프링 부트 테스트와 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 등의 상태를 검증한다.
📌 .andExpect(content().string(hello))
- mvc.perform의 결과를 검증한다.
- 응답 본문의 내용을 검증한다.
수동으로도 Application.java 파일에서 main 메소드를 실행시킨다
또한 http://localhost:8080/hello 에 접속해보면
테스트 코드는 꼭 해보아야하며, 수동으로 검증하고 테스트 코드를 작성하는 순서는 없음
늘 테스트 코드로 먼저 검증한 뒤, 정말 못 믿겠을때 프로젝트를 실행해서 확인해야함
3️⃣ 롬복 소개 및 설치하기
- 롬복은 Getter, Setter, 기본 생성자, ToString 등을 어노테이션으로 자동 생성해줌
💚 build.gradle 파일에 추가
compile('org.projectlombok:lombok')
💥Gradle Could not find method compile() 오류 발생
compile, runtime, testCompile, testRuntime 은 Gradle 4.10 (2018.8.27) 이래로 deprecate 되었다.
그리고 Gradle 7.0 (2021.4.9) 부터 삭제되었다.
필자는 Gradle 7.3.3 을 이용하고 있어서 삭제된 명령을 사용했으므로 오류가 발생했었다.
삭제된 네 명령은 각각 implementation, runtimeOnly, testImplementation, testRuntimeOnly 으로 대체되었다.
따라서 compile 을 implementation 으로 수정하여 오류를 해결
implementation('org.projectlombok:lombok')
로 작성해주기~!
💚 Intellij lombok 플러그인 추가
를 해야하는데 market에 lombok이 없었다... 찾아보니
IntelliJ 2020.03 이후 버전에서는 기본Plugin으로 Lombok이 설치되어 있습니다.
라고 한다~
설치는 가볍게 패스
💚 롬북 설정 (Enalbe annotation processing 체크)
4️⃣ Hello Controller 코드를 롬복으로 전환하기
💚HelloResponseDto 클래스 생성
package com.jojoldu.book.springboot.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이 없는 필드는 생성자에 포함되지 않습니다.
💚 HelloResponseDtoTest 클래스 생성
롬복 작동 테스트 위한 테스트 코드를 작성하자
package com.jojoldu.book.springboot.web.dto;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
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와 같이 메소드를 이어서 사용할 수 있다.
롬복의 @Getter로 get 메소드가, @RequiredArgsConstructor로 생성자가 자동으로 생성되는것이 증명
💚 HelloController 메소드 추가
- HelloController에서도 새로 만든 ResponseDto를 사용하도록 코드 추가
- name과 amount는 API를 호출하는 곳에서 넘겨준 값들임
@GetMapping("/hello/dto")
public HelloResponseDto helloDto(@RequestParam("name") String name,
@RequestParam("amount") int amount){
return new HelloResponseDto(name, amount);
}
💚 HelloControllerTest 메소드 추가
추가된 API를 테스트하는 코드 추가
import static org.hamcrest.Matchers.is;
@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로 검증
Json이 return되는 API 역시 정상적으로 테스트가 통과하는 것을 확인할 수 있다
💻 reference
'Server > Spring Boot' 카테고리의 다른 글
[Spring Boot] 빌더(Builder) 패턴의 정의, 생성자 패턴 빌더 패턴 비교 (0) | 2023.09.25 |
---|---|
[Spring] 스프링 의존성 주입 종류와 @RequiredArgsConstructor 어노테이션을 사용한 생성자 주입 (0) | 2023.09.24 |
[Chapter 03] 스프링 부트에서 JPA로 데이터베이스 다뤄보자 (1) - 등록 (0) | 2023.09.24 |
[Chapter 01] 인텔리제이로 스프링 부트 시작하기 (0) | 2023.09.15 |
[Spring Boot] 스프링의 콘셉트(IoC, DI, AOP, PSA) (0) | 2023.09.13 |