(단위)테스트 코드를 작성하는 이유
- 개발단계 초기에 문제를 발견하게 도와줌
- 개발자가 나중에 코드를 리팩토링하거나 라이브러리 업그레이드 등에서 기존 기능이 올바르게 작동하는지 확인할 수 있음(예, 회귀테스트)
- 기능에 대한 불확실성을 감소시킬 수 있음
- 시스템에 대한 실제 문서를 제공함. 즉, 단위 테스트 자체가 문서로 사용할 수 있음
단위 테스트를 사용하기 전의 개발방식
- 코드를 작성
- 프로그램(Tomcat) 실행
- Postman과 같은 API 테스트 도구로 HTTP 요청
- 요청 결과를 System.out.println()로 눈으로 검증
- 결과가 다르면 다시 프로그램(Tomcat)을 중지하고 코드를 수정
여기서 2~5는 매번 코드를 수정할 때마다 반복해야함
- 왜 계속 톰캣을 내렸다가 다시 실행하는 일을 반복할까?
- 이는 테스트 코드가 없다 보니 눈과 손으로 직접 수정된 기능을 확인할 수 밖에 없기 때문
테스트 코드가 있다면?
- 자동검증이 가능
- 개발자가 만든 기능을 안전하게 보호
- 기존에 잘되던 A기능에 문제가 생긴 것을 발견
- 서비스의 모든 기능을 테스트할 수는 없음
- 기존 기능이 잘 작동되는 것을 보장
메인 클래스
package com.danny.makewebalone;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MakeWebAloneApplication {
public static void main(String[] args) {
SpringApplication.run(MakeWebAloneApplication.class, args);
}
}
교재에서는 메인 클래스를 직접 생성하였지만
본인은 프로젝트 생성 시에 같이 만들어져있습니다.
@SpringBootApplication
- 스프링 부트의 자동 설정, 스프링 Bean읽기와 생성을 모두 자동으로 설정
- 톰캣을 실행하지 않아도 내장 WAS로 내부에서 실행 가능
Hello Controller
package com.danny.makewebalone.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를 만들어 줌
Hello Controller 테스트 코드 작성하기
package com.danny.makewebalone.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.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.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));
}
JUnit이란? 단위 테스트 도구
@RunWith(SpringRunner.class)
- SpringRunner라는 스프링 실행자를 사용
- 즉, 스프링 부트 테스트와 JUnit사이에 연결자 역할
@WebMvcTest(controllers = HelloController.class)
- 여러 스프링 테스트 어노테이션 중, Web(Spring MVC)에 집중할 수 있는 어노테이션
- 선언할 경우 @Controller, @ControllerAdvice등을 사용할 수 있음
@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, 400, 500 등의 상태를 검증
- 여기서 OK 즉, 200인지 아닌지를 검증
.andExpect(content().string(hello));
- mvc.perform의 결과를 검증
- 응답 본문의 내용을 검증
- Controller에서 "hello"를 리턴하기 때문에 이 값이 맞는지 검증
Test코드 실행 결과
- 버튼을 누르면 다음과 같이 정상적으로 테스트 결과가 나옴
만약 리턴값 검증을 Hello가 아닌 다른 값을 넣는다면?
- Tests failed가 나오고 다르게 입력한 리턴값과 실제 리턴값을 알려줌
Main 메소드 실행 결과
- 정상적으로 실행이 됨
롬복이란?
- 자바 개발자들의 필수 라이브러리
- Getter, Setter, 기본생성자, toString 등을 어노테이션으로 자동 생성
Hello ControllerDto
package com.danny.makewebalone.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.danny.makewebalone.web.dto;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class HelloResponseDtoTest {
@Test
public void 롬복_기능_테스트() {
//given
String name = "danny";
int amount = 1000;
//when
HelloResponseDto dto = new HelloResponseDto(name, amount);
//then
assertThat(dto.getName()).isEqualTo(name);
assertThat(dto.getAmount()).isEqualTo(amount);
}
}
assertThat
- assertThatj라는 테스트 검증 라이브러리의 검증 메소드
- 검증하고 싶은 대상을 메소드 인자로 받음
- 메소드 체이닝이 지원되어 isEqualTo와 같이 메소드를 이어서 사용할 수 있음
- assertThat에 있는 값과 isEqualTo의 값을 비교해서 같을 때만 성공
HelloController에 dto컨트롤러 추가
@GetMapping("/hello/dto")
public HelloResponseDto helloDto(@RequestParam("name") String name,
@RequestParam("amount") int amount) {
return new HelloResponseDto(name, amount);
}
@RequestParam
- 외부에서 API로 넘긴 파라미터를 가져오는 어노테이션
- (@RequestParam("name")이란 이름으로 넘긴 파라미터를 메소드 파라미터 name(String name)에 저장
HelloControllerDto 테스트 코드 작성하기
@Test
public void helloDto가_리턴된다() throws Exception {
String name = "danny";
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로 검증
Test 결과
Passed
'스프링 부트와 AWS' 카테고리의 다른 글
03장. 스프링 부트에서 JPA로 데이터베이스 다뤄보자03 (0) | 2022.11.14 |
---|---|
03장. 스프링 부트에서 JPA로 데이터베이스 다뤄보자02 (0) | 2022.11.11 |
03장. 스프링 부트에서 JPA로 데이터베이스 다뤄보자01 (0) | 2022.11.11 |
01장. 인텔리제이로 스프링 부트 시작하기 (0) | 2022.11.11 |
스프링 부트와 AWS로 혼자 구현하는 웹 서비스 (0) | 2022.11.11 |
댓글