Spring-boot x JUnit
1. JUnit이란
- Java의 단위 테스트 도구 및 테스트 프레임워크이다.
- 함수별로 테스트가 가능하며, 개발자는 문서뿐만이 아니라 Test class 자체를 남겨 Class에 대한 history를 인수인계 할 수 있다.
1-1. TDD (Test Driven Development)
-
테스트 주도 개발
: 테스트가 개발을 이끌어 나간다.
-
함수 작성 시 종료 조건을 먼저 설계한 후에 코드를 작성한다라고 생각하면 된다.
-
TDD 개발 주기
- RED : 항상 실패하는 테스트를 먼저 작성
- GREEN : 테스트에 통과하는 프로덕션 코드 작성
- REFACTOR : 테스트가 통과하면 프로덕션 코드에 대해서 중복 코드 제거 및 리팩토링
1-1-1. TDD가 왜 필요한가?
-
일반적인 개발 주기
-
일반적인 개발 주기는 요구사항 분석 -> 설계 -> 개발 -> 테스트 -> 배포
를 따른다.
이때 문제가 되는 사항은 요구사항은 언제나 명확하지 않다. 따라서 설계는 처음부터 완벽할 수 없다. 그렇기에 테스트 후 새로 코드를 짜야 하며, 요구사항들이 겹겹이 코드에 쌓이기 때문에 코드 재사용성은 떨어지고 품질 또한 떨어진다.
-
작은 코드를 삽입해도, 전체 시스템을 테스트 해야 하기 때문에 테스트 비용이 점점 커진다.
-
TDD 개발 주기
- 테스트 코드를 미리 작성한 후에 코드를 개발한다는 점에서 일반적인 개발 방식과 방식과 큰 차이가 있다. 디자인 단계에서 프로그램의 목적을 미리 정의해야하며, 무엇에 대해서 테스트를 할 지 미리 정의 (테스트 케이스) 해야만 한다.
- 테스트 코드 작성중에 나타나는 버그들에 대해서는 테스트 케이스에 추가하며, 설계를 개선한다. 이러한 일련의 과정을 반복해 코드의 버그가 줄어들고 소스코드는 간결해진다.
- 이러한 TDD 방식에도 단점이 존재하는데, 바로 생산성이 저하된다는것이다. 이러한 점을 개선하고자 노력해야한다.
-
TDD에서 가장 유명한 툴이 바로 Junit 이다.
1-2. Controller 테스트 코드 작성
Controller 작성
-
작성하기 전에 Test Controller를 작성해보자.
package com.test.blog.test.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/*
RestController 컨트롤러에서 반횐되는 값을 JSON 형식으로 변경해준다.
*/
@RestController
public class TestController {
@GetMapping("/")
public String test(){
return "test";
}
}
- @RestController: 컨트롤러에서 반환되는 값을 JSON 형식으로 변환해준다. 또한 @ResponseBody를 각 메소드마다 선언했던 것을 한번에 사용할 수 있게 해준다.
- @GetMapping: HTTP Method인 Get인 요청을 받을 수 있는 API를 만들어 준다. (예전에는 @RequestMapping(method = RequestMethod.GET))
- 위와 같이 작성한 후 서버를 실행시켜 localhost:8080 으로 접속하면 아래와 같이 표기된다.
테스트 코드 작성
-
클래스 우클릭 후 Go To > Test 를 클릭
-
사용하고자 하는 Junit 버전과 테스트 클래스 이름, 테스트 하고자 하는 함수를 설정 후 OK 버튼을 두르면 Test 코드 템플릿이 자동으로 만들어진다.
-
테스트 코드 작성
package com.test.blog.test.controller;
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.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@RunWith(SpringRunner.class) // SpringRunner class의 생성자 실행
@WebMvcTest(controllers = TestController.class) // Web MVC에 집중할 수 있는어노테이션
public class TestControllerTest {
@Autowired
private MockMvc mvc;
@Test
public void test1() throws Exception{
final String test = "test";
mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(content().string(test));
}
}
- @RunWIth(Class): 타 클래스의 생성자를 실행할 수 있는 어노테이션
- 여기서는 SpringRunner라는 스프링 실행자를 사용
- 즉, 스프링 부트 테스트와 JUnit 사이에 연결자 역할
- @WebMvcTest
- 여러 스프링 테스트 어노테이션 중, Web(Spring MVC)에 집중할 수 있는 어노테이션
- 선언할 경우 @Controller, @ControllerAdvice 등을 사용 가능
- 단, @Service, @Component, @Repository 등은 사용할 수 없다
- 여기서는 컨트롤러만 사용한다
- 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의 결과를 검증한다
- 응답 본문의 내용을 검증한다
1-3. Lombok 설치
-
build.gradle > dependencies 에 다음을 추가
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
-
Intellj lombok 플러그인 추가
- Intellj > File > Settings... > Plugins 클릭
Lombok
을 검색해 install
- 같은 창에서 좌측의 Build, Execution, Deployment > Compiler > Annotation Processors 클릭 후
Enable annotation processing
을 체크
1-3-1. Lombok x DTO 테스트
TestDTO 클래스 작성
package com.test.blog.test.dto;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public class TestDTO {
private final String value;
private final int id;
}
- @Getter : 필드의 getter 메소드를 자동으로 만들어줌
- @RequiredArgsConstructor : final 키워드가 붙은 상수형 필드 변수들에 대해서 생성자를 만들어줌. final 키워드가 없는 필드는 생성자에 포함되지 않음.
- DTO (Data Transfer Object) : 데이터를 담은 자바 빈즈
- VO (Value Object): DTO와 동일하지만 read-only
- Entity : DB Table과 1 : 1 로 매칭이 되는 class. DB 테이블에 존재하는 컬럼만 필드로 가져야한다.
Test Code 작성
package com.test.blog.test.dto;
import static org.assertj.core.api.Assertions.*;
import org.junit.Test;
public class TestDTOTest {
@Test
public void DTO_X_LombokTest(){
String value = "test";
int id = 0;
TestDTO dto = new TestDTO(value, id);
assertThat(dto.getId()).isEqualTo(id);
assertThat(dto.getValue()).isEqualTo(value);
}
}
- assertThat : asserj라는 테스트 검증 라이브러리 검증 메소드
- isEqualTo : 검증하고자하는 대상을 메소드 인자로 받는다. 메소드 체이닝이 지원돼 isEqualTo와 같이 메소드를 이어서 쓸 수 있다.
1-3-2. Test controller X DTO X 테스트 코드 작성
1. TestController 작성
package com.test.blog.test.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.test.blog.test.dto.TestDTO;
/*
RestController 컨트롤러에서 반횐되는 값을 JSON 형식으로 변경해준다.
*/
@RestController
public class TestController {
@GetMapping("/")
public String test(){
return "test";
}
@GetMapping("/test")
public TestDTO setTestDTO(@RequestParam("value") String value,
@RequestParam("id") int id ){
return new TestDTO(value, id);
}
}
- @RequestParam: url 주소로 값을 받아올 수 있음. 위와 같은 코드 일 때, `http://localhost:8080/test?value=TEST&id=1` 로 값을 전송할 수 있음.
2. TestCode 작성
@Test
public void testDTO() throws Exception {
final String value = "TEST";
final int id = 0;
mvc.perform(get("/test").param("value", value).param("id", String.valueOf(id)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.value", CoreMatchers.is(value))) // $를 기준으로 필드명 명시
.andExpect(jsonPath("$.id", CoreMatchers.is(id)));
}
- param : http get방식에서 전달될수 있는 요청 파라미터의 값을 삽입. String 데이터만 허용.
- jsonPath : JSON 형태의 값을 검증. $을 기준으로 필드명을 명시할 수 있음.
Author And Source
이 문제에 관하여(Spring-boot x JUnit), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://velog.io/@jiseok/Spring-boot-x-JUnit
저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
테스트 주도 개발
: 테스트가 개발을 이끌어 나간다.
함수 작성 시 종료 조건을 먼저 설계한 후에 코드를 작성한다라고 생각하면 된다.
TDD 개발 주기
- RED : 항상 실패하는 테스트를 먼저 작성
- GREEN : 테스트에 통과하는 프로덕션 코드 작성
- REFACTOR : 테스트가 통과하면 프로덕션 코드에 대해서 중복 코드 제거 및 리팩토링
일반적인 개발 주기
-
일반적인 개발 주기는
요구사항 분석 -> 설계 -> 개발 -> 테스트 -> 배포
를 따른다.
이때 문제가 되는 사항은 요구사항은 언제나 명확하지 않다. 따라서 설계는 처음부터 완벽할 수 없다. 그렇기에 테스트 후 새로 코드를 짜야 하며, 요구사항들이 겹겹이 코드에 쌓이기 때문에 코드 재사용성은 떨어지고 품질 또한 떨어진다. -
작은 코드를 삽입해도, 전체 시스템을 테스트 해야 하기 때문에 테스트 비용이 점점 커진다.
TDD 개발 주기
- 테스트 코드를 미리 작성한 후에 코드를 개발한다는 점에서 일반적인 개발 방식과 방식과 큰 차이가 있다. 디자인 단계에서 프로그램의 목적을 미리 정의해야하며, 무엇에 대해서 테스트를 할 지 미리 정의 (테스트 케이스) 해야만 한다.
- 테스트 코드 작성중에 나타나는 버그들에 대해서는 테스트 케이스에 추가하며, 설계를 개선한다. 이러한 일련의 과정을 반복해 코드의 버그가 줄어들고 소스코드는 간결해진다.
- 이러한 TDD 방식에도 단점이 존재하는데, 바로 생산성이 저하된다는것이다. 이러한 점을 개선하고자 노력해야한다.
TDD에서 가장 유명한 툴이 바로 Junit 이다.
Controller 작성
작성하기 전에 Test Controller를 작성해보자.
package com.test.blog.test.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/*
RestController 컨트롤러에서 반횐되는 값을 JSON 형식으로 변경해준다.
*/
@RestController
public class TestController {
@GetMapping("/")
public String test(){
return "test";
}
}
- @RestController: 컨트롤러에서 반환되는 값을 JSON 형식으로 변환해준다. 또한 @ResponseBody를 각 메소드마다 선언했던 것을 한번에 사용할 수 있게 해준다.
- @GetMapping: HTTP Method인 Get인 요청을 받을 수 있는 API를 만들어 준다. (예전에는 @RequestMapping(method = RequestMethod.GET))
- 위와 같이 작성한 후 서버를 실행시켜 localhost:8080 으로 접속하면 아래와 같이 표기된다.
테스트 코드 작성
클래스 우클릭 후 Go To > Test 를 클릭
사용하고자 하는 Junit 버전과 테스트 클래스 이름, 테스트 하고자 하는 함수를 설정 후 OK 버튼을 두르면 Test 코드 템플릿이 자동으로 만들어진다.
테스트 코드 작성
package com.test.blog.test.controller;
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.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@RunWith(SpringRunner.class) // SpringRunner class의 생성자 실행
@WebMvcTest(controllers = TestController.class) // Web MVC에 집중할 수 있는어노테이션
public class TestControllerTest {
@Autowired
private MockMvc mvc;
@Test
public void test1() throws Exception{
final String test = "test";
mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(content().string(test));
}
}
- @RunWIth(Class): 타 클래스의 생성자를 실행할 수 있는 어노테이션
- 여기서는 SpringRunner라는 스프링 실행자를 사용
- 즉, 스프링 부트 테스트와 JUnit 사이에 연결자 역할
- @WebMvcTest
- 여러 스프링 테스트 어노테이션 중, Web(Spring MVC)에 집중할 수 있는 어노테이션
- 선언할 경우 @Controller, @ControllerAdvice 등을 사용 가능
- 단, @Service, @Component, @Repository 등은 사용할 수 없다
- 여기서는 컨트롤러만 사용한다
- 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의 결과를 검증한다
- 응답 본문의 내용을 검증한다
build.gradle > dependencies 에 다음을 추가
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
Intellj lombok 플러그인 추가
- Intellj > File > Settings... > Plugins 클릭
Lombok
을 검색해 install
- 같은 창에서 좌측의 Build, Execution, Deployment > Compiler > Annotation Processors 클릭 후
Enable annotation processing
을 체크
TestDTO 클래스 작성
package com.test.blog.test.dto;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public class TestDTO {
private final String value;
private final int id;
}
- VO (Value Object): DTO와 동일하지만 read-only
- Entity : DB Table과 1 : 1 로 매칭이 되는 class. DB 테이블에 존재하는 컬럼만 필드로 가져야한다.
Test Code 작성
package com.test.blog.test.dto;
import static org.assertj.core.api.Assertions.*;
import org.junit.Test;
public class TestDTOTest {
@Test
public void DTO_X_LombokTest(){
String value = "test";
int id = 0;
TestDTO dto = new TestDTO(value, id);
assertThat(dto.getId()).isEqualTo(id);
assertThat(dto.getValue()).isEqualTo(value);
}
}
1. TestController 작성
package com.test.blog.test.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.test.blog.test.dto.TestDTO;
/*
RestController 컨트롤러에서 반횐되는 값을 JSON 형식으로 변경해준다.
*/
@RestController
public class TestController {
@GetMapping("/")
public String test(){
return "test";
}
@GetMapping("/test")
public TestDTO setTestDTO(@RequestParam("value") String value,
@RequestParam("id") int id ){
return new TestDTO(value, id);
}
}
- @RequestParam: url 주소로 값을 받아올 수 있음. 위와 같은 코드 일 때, `http://localhost:8080/test?value=TEST&id=1` 로 값을 전송할 수 있음.
2. TestCode 작성
@Test
public void testDTO() throws Exception {
final String value = "TEST";
final int id = 0;
mvc.perform(get("/test").param("value", value).param("id", String.valueOf(id)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.value", CoreMatchers.is(value))) // $를 기준으로 필드명 명시
.andExpect(jsonPath("$.id", CoreMatchers.is(id)));
}
- param : http get방식에서 전달될수 있는 요청 파라미터의 값을 삽입. String 데이터만 허용.
- jsonPath : JSON 형태의 값을 검증. $을 기준으로 필드명을 명시할 수 있음.
Author And Source
이 문제에 관하여(Spring-boot x JUnit), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jiseok/Spring-boot-x-JUnit저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)