02. 스프링부트에서 테스트 코드를 작성하자
대부분의 서비스 회사가 테스트 코드에 관해 요구하는 추세.
TDD나 단위 테스트를 할 줄 알아야 함.
=> 테스트 코드 작성 기본 배우기
2-1. 테스트 코드 소개
TDD : 테스트가 주도하는 개발 = 테스트 고드를 먼저 작성
- 항상 실패하는 테스트를 먼저 작성하고
- 테스트가 통과하는 프로덕션 코드를 작성
- 테스트가 통과하면 프로덕션 코드를 리팩토링
단위 테스트 : 기능 단위의 테스트 코드 작성
테스트 코드 먼저 작성 할 필요 x, 리팩토링 포함 x
1. 단위 테스트 코드 사용 이유
1) 빠른 피드백
- 단위 테스트 코드 사용 이전 개발 방식
1) 코드 작성
2) 프로그램 (톰캣) 실행
3) postman 같은 api 도구로 http 요청
4) 요청 결과 system.out.println()으로 눈으로 검증
5) 결과 다르면 다시 프로그램 중지하고 코드 수정
코드 수정 할 때마다 2-5번 과정을 반복했어야했음
- 테스트 코드가 없어 손으로 직접 수정된 기능 확인 위해 톰캣 올렸다 내림 -> 재시작 시간 소요
테스트 코드 작성 시 이런 문제 해결 -> 톰캣 올렸다 내릴 필요 없음
2 )자동 검증 가능
System.out.println()을 사용하여 눈으로 수동 검증 했었음
단위 테스트 실행 시 자동검증 가능
3) 기존 기능 잘 작동되게 보장
새로운 기능이 추가될 때 기존에 잘 되던 기능에 문제가 생기기도 함-> 빈번
하나의 기능 추가시 많은 자원이 들음 => 서비스의 모든 기능을 테스트 할 수 없음
여러 경우를 모두 테스트코드로 구현해 놓고 수행하면 문제를 조기에 찾을 수 있음.
2. 테스트 코드 작성을 돕는 프레임워크
xUnit : 개발환경(x)에 따른 Unit테스트를 도와주는 도구
JUnit - Java
DBUnit - DB
CppUnit- C++
NUnit - .net
테스트 코드는 100% 익혀야 할 기술이자 습관
2-2 Hello Controller 테스트 코드 작성하기
패키지 생성
일반적인 패키지 명 : 웹사이트 주소의 역순
ex) abc.springboot.com ->패키지명 : com.springboot.abc
1. Application
이 프로젝트의 메인 클래스가 될 것.
import org.springframework.boot.SpringApplication;
import orh.spirngframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
pulbic class Application{
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
}
@SpringBootApplication :
스프링부트의 자동 설정, bean읽기와 생성등이 모두 자동 설정됨.
이 어노테이션이 있는 위치부터 설정을 읽어감 -> 항상 프로젝트 최상단에 위치해야됨.
SpringApplication.run
- 내장 WAS 실행
내장 WAS란 ?
- WAS ( Web Application Server)를 외부에 두지 않고, 어플리케이션을 실행 할 때 내부에서 WAS가 실행되는 것
- 톰캣 치할 필요가 없게됨 -> jar파일로 실행하면 됨.
- 언제 어디서나 같은 환경에서 스프링부트 배포 가능
- 외장 WAS 쓸 경우 모든 서버에서 WAS종류와 버전, 설정을 일치 시켜야함
- 여러개의 컴퓨터에서 WAS의 버전 올릴경우 -> 실수 여지 많고 시간도 많이 필요
2. Controller
테스트를 위한 클래스
기존 패키지 안에 web 패키지 생성 후 Controller 파일 만들기.
앞으로 컨트롤러 관련 클래스들 모두 web에 담을 예정
간단한 API만들기
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController{
@GetMapping("/hello")
pulbic String hello(){
return "hello";
}
}
@RestController
- 컨트롤러를 JSON을 반환하는 컨트롤러로 만들어줌
- 이전에는 @ResponseBody를 각 메소드마다 선언 해주던걸 이제 한번에 사용할 수 있게함
JSON이란
- JavaScript Object Notation으로, "키-값 쌍"으로 이루어진 데이터 오브젝트를 전달하기 위해 인간이 읽을 수 있는 텍스트를 사용하는 개방형 표준포맷
- 인터넷에서 자료를 주고 받을 때 그 자료를 표현하는 방법으로 알려져 있다.
@GetMapping
- HTTD Method인 Get의 요청을 받을 수 있는 API 생성해줌
- /hello 로 요청이 오면 return값을 반환하는 기능 갖음
3. Test
WAS를 실행하지 않고 테스트 코드로 검증
테스트 클래스 : 대상 클래스 이름에 Test를 붙임
HelloControllerTest 생성
package com.springboot.yongeun.first.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 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) //test 진행시 junit에 내장된 실행자 외 실행자 실행. springboot test와 junit연결
@WebMvcTest(controllers=HelloController.class) //web에 집중할 수 있는 annotation
public class HelloControllerTest {
@Autowired //bean 주입받음
private MockMvc mvc; //웹 api test시 사용 / 스프링 mvc 테스트 시작점/ 이 클래스 통해 http get, post등 api test가능
@Test
public void hello가_리턴된다() throws Exception{
String hello="hello";
mvc.perform(get("/hello")) //MockMvc 클래스를 통해 /hello 주소로 HTTP GET 요청을 함
.andExpect(status().isOk()) // mvc.perform 결과 검증 -> http header의 status 검증 (200,400,500)
.andExpect(content().string(hello)); //응답 본문의 내용 검증 ->hello return 해줬는지
}
}
@RunWith(SpringRunner.class)
- 테스트 실행 시 JUnit에 내장된 실행자 외 다른 실행자 실행
- SpringRunner라는 스프링 실행자 사용
- 스프링부트 테스트와 JUnit 사이 연결자 역할
추가 검색
1) @SpringbootTest는 application context를 전부 로딩함 -> 무거운 project 될 수도
2) @RunWith은 @Autowired, @MockBean에 해당하는 것들에게만 application context로딩
3) SpringJUnitClassRunner, JUnitTest 라이브러리를 SpringTestContextFramework와 결합 시킴
@WebMvcTest
- Web에 집중할 수 잇는 어노테이션
- @Service, @Component, @Repository 등 사용 불가능
- @Controller, @ControllerAdvice 등은 사용 가능 -> 여기서는 컨트롤러만 사용하기 때문에 선언함
@Autowired
- 스프링이 관리하는 bean을 주입받음
@private MockMvc mvc
- 웹 API를 테스트 할 때 사용
- 이 클래스 통해 HTTP GET, POST등에 대한 API 테스트 할 수 있음
- 스프링 MVC 테스트의 시작점
@mvc.perform(get("/hello"))
- MockMVC를 통해 /hello주소로 HTTP GET요청
- 아래 여러검증 이어서 진행 가능
.andExpect(status().isOk())
- mvc.perform의 결과 검증
- HTTP Header의 Status 검증
- 200, 500, 404등의 상태 검증 -> Ok(200)인지 아닌지 검증
.andExpect(content().string(hello))
- mvc.perform의 결과 검증
- 응답 본문의 내용검증
- controller에서 hello를 return 함 -> 이 값이 맞는지 검증
검증용으로 선언한 .andExpect(status().isOk())와 .andExpect(content().string(hello))가 테스트를 통과함
수동으로 정상적 값이 출력되는지 확인
main실행 -> tomcat서버가 8080포트로 실행됨 -> localhost:8080/hello로 접속
2-3 롬복 소개 및 설치하기
자바 개발자들의 필수 라이브러리 롬복
getter, setter, 기본생성자, toString등을 어노테이션으로 자동생성해줌
build.gradle에 롬복 추가
dependencies{
implementation('org.projectlombok:lombok') }
plugin에서 lombok 설치 후 settings>build>compiler>Annotation Processors > Enable annotation processing 체크
2-4 Hello Controller 코드를 롬복으로 전환하기
web 패키지에 dto 패키지 추가
모든 응답 Dto를 Dto 패키지에 추가
1. HelloResponseDto에 lombok 붙이기
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public class HelloResponseDto{
private final String name;
private final int amount;
}
@Getter
- 선언된 모든 필드의 get메소드를 생성해줌
@RequiredArgsConstructor
- 선언된 모든 final 필드가 포함된 생성자를 생성해줌
- final이 없는 필드는 생성자에 포함되지 않음
- 초기화 되지 않은 final field나 @NonNull이 붙은 field에 생성자 생성해줌
2. HelloResponseDtoTest
Dto에 적용된 lombok이 잘 작동하는지 확인하는 test code
name, amount를 잘 get하는지 확인
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
//dto.getName() : 검증하고 싶은 대상
assertThat(dto.getName()).isEqualTo(name);
assertThat(dto.getAmount()).isEqualTo(amount);
}
}
assertThat
- assertj 라는 테스트 검증 라이브러리의 검증메소드
- 검증하고 싶은 대상 메소드 인자로 받음
- 메소드 체이닝 지원
isEqualTo
- assertj의 동등 비교 메소드
- assertThat에 있는 값과 isEqualTo의 값 비교해서 같을 때만 성공
JUnit의 기본 assertThat이 아닌 assertj의 assertThat 사용
assertj도 JUnit에서 자동으로 라이브러리 등록해줌
assertj의 장점
- 추가적 라이브러리가 필요하지 않음
JUnit의 assertThat을 쓰면 is()와 같이 CoreMatches 라이브러리가 필요함
- 자동완성이 좀 더 확실하게 지원됨
3. HelloController 에 ResponseDto 적용하기
HelloController에 코드 추가
@GetMapping("/hello/Dto")
public HelloResponseDto helloDto(@RequestParam("name") String name,
@RequestParam("amount") int amount){
return new HelloResponseDto(name, amount);
}
@RequestParam
@RequestParam ("가져올 data이름") datatype 가져올 data담을 변수
- 외부에서 API로 넘긴 파라미터를 가져오는 annotation
- 외부에서 name(@RequestParam("name"))이란 이름으로 넘긴 파라미터를
메소드 파라미터 name(String name)에 저장
4. HelloControllerTest
name과 amount : API를 호출하는 곳에서 넘겨준 값들
package com.springboot.yongeun.first.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.client.match.MockRestRequestMatchers.jsonPath;
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) //test 진행시 junit에 내장된 실행자 외 실행자 실행. springboot test와 junit연결
@WebMvcTest
public class HelloControllerTest {
@Autowired //bean 주입받음
private MockMvc mvc; //웹 api test시 사용 / 스프링 mvc 테스트 시작점/ 이 클래스 통해 http get, post등 api test가능
@Test
public void hello가_리턴된다() throws Exception{
String hello="hello";
mvc.perform(get("/hello")) //MockMvc 클래스를 통해 /hello 주소로 HTTP GET 요청을 함
.andExpect(status().isOk()) // mvc.perform 결과 검증 -> http header의 status 검증 (200,400,500)
.andExpect(content().string(hello)); //응답 본문의 내용 검증 ->hello return 해줬는지
}
@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로 입력
=> 근데 난 마지막 두줄에서 에러가 났다 다들 어떻게 하셨는지 궁금하다.
'서적 공부 > 스프링부트와 AWS로 혼자 구현하는 웹 서비스' 카테고리의 다른 글
Annotation 정리 (0) | 2022.04.04 |
---|---|
1장 인텔리제이로 스프링 부트 시작하기 (0) | 2022.03.30 |