이 글은 이동욱 님의 스프링 부트와 AWS로 혼자 구현하는 웹 서비스를 읽고 정리한 글입니다.
내용보다 중요한 점, 추가적으로 알아본 것 등을 위주로 적었습니다.
http://www.yes24.com/Product/Goods/83849117
많은 사람들의 리뷰, 추천으로 이 책을 정리하려 한다.
스프링부트의 기본을 알고, 그것을 통해 AWS를 접하고자 하는 사람에게 좋을 것 같아서 이 책으로 결정했다.
02장. 스프링 부트에서 테스트 코드를 작성하자
테스트 코드 소개
TDD
TDD는 Test Driven Development의 약자로 ‘테스트 주도 개발’이라고 한다.
외부의 요구 조건이 많이 바뀔 경우, 팀원이 많은 경우 등 보다 탄탄하게 코드를 짜야 하는 경우에 이러한 개발을 한다.
애초에 테스트 코드까지 2개의 코드를 짜야하니 생산성이 떨어지지만, 나중이 편해진다.
http://clipsoft.co.kr/wp/blog/tddtest-driven-development-%EB%B0%A9%EB%B2%95%EB%A1%A0/
테스트 코드는 왜 짜야 하는가?
백엔드 개발의 경우, 코딩 후 프로그램 실행을 한 뒤 직접 요청을 해서 검증을 했다. 여기서 3가지 문제점이 발생한다.
- 테스트마다 서버를 실행해야 한다.
만약, 코드를 리펙토링한 후 테스트해야 하는 케이스가 만 단위를 넘어가면 어떻게 될까? 한 케이스마다 서버를 올렸다 내렸다, 번거로움의 연속이다. 서버를 직접 실행하지 않고, 단위 테스트 코드를 작성해야 한다.
- 직접 눈으로 검증해야 한다.
로그나 println()등의 함수로 직접 검증해야 한다. 마찬가지로 테스트 케이스가 커지면 큰일난다. 자동검증을 해주는 테스트 코드를 작성해야 한다.
- 개발자가 만든 기능이 보호받지 못 한다.
새로운 기능 때문에 기존의 기능이 작동하지 못하는 경우가 있다면, 기존의 기능을 테스트하는 코드가 있어야 금방 알아차리고 디버깅할 수 있다.
테스트 프레임워크 xUnit
가장 대중적인 테스트 프레임워크인데, 대표적인 프레임워크는 다음과 같다.
- JUnit - Java
- DBUnit - DB
- CppUnit - C++
- NUnit - .net
당연히 우리는 JUnit을 쓸 것이다. 책에선 JUnit4를 썼지만, 나는 JUnit5를 쓰겠다.
Hello Controller 테스트 코드 작성하기
본격적인 코딩 전에, 내장 WAS?
WAS는 Web Application Server, 웹 어플리케이션 서버를 말하는데, 스프링 부트는 별도로 WAS를 두지 않고 내장 WAS인 톰캣을 사용하도록 권장한다. 언제 어디서나 같은 환경에서 스프링 부트를 배포할 수 있기 때문이다.
성능상 이슈가 있을 수도 있지만 웬만큼 큰 서비스에서도 내장 WAS를 사용해도 될 정도이다.
이제 다음과 같은 코드를 "HelloController.java" 파일에 추가한다.
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
}
그 후, 클래스명에 커서를 두고 Alt + Enter ( Option + Enter )를 통해 테스트 클래스를 생성하면 자동으로 생성해준다.
@ExtendWith(SpringExtension.class)
@WebMvcTest(controllers = HelloController.class)
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));
}
}
- 테스트 코드의 작성은 협업과 리팩토링 등을 위해 알아보기 쉽게 해야한다. 따라서 함수명을 한글로 설명하듯이 적어도 된다.
- get(), status(), content() 함수는 static으로 import해야 코드와 같이 쓸 수 있다.
- 책과 다른 코드가 몇 있다. 자세한 것은 책의 저자의 블로그에 정리되어 있다.
https://jojoldu.tistory.com/539
코드는 Controller layer의 코드를 Test한 것이다. 즉, 실제로 서버를 실행시키지 않고 컨트롤러가 잘 작동하는지 보기 위해 가짜(Mock) MVC를 작동시킨 것이다. 시간, 자원 등을 아낀 것이다.
단위 테스트 (Unit Test)는 정말 중요하다. 이에 대해 정리한 게시글이다. 이 글을 보면 우리가 진행한 테스트는 narrow integration test이다.
Hello Controller 코드를 롬복으로 전환하기
책에서는 lombok을 사용 설정하는 데에 많은 시간과 페이지를 투자했지만, 경험상 요즘은 dependency에 입력하면 자동으로 되는 것 같아서 건너뛰겠다.
dto에 관한 내용은 다음 게시글을 참고하자. https://studyandwrite.tistory.com/402
web 패키지에 dto 패키지를 추가하고 다음과 같은 파일을 생성한다.
@Getter
@RequiredArgsConstructor
public class HelloResponseDto {
private final String name;
private final int amount;
}
보이는 어노테이션 2개가 lombok이 제공해주는 어노테이션이다. lombok은 클래스 단위에서 많은 편의 기능을 제공해주는 라이브러리(의존성)이다. lombok이 제공하는 많은 기능들을 정리해 둔 블로그가 많으니 찾아보길 바란다.
위 코드의 @Getter는 변수들의 getter를 자동 생성해주고 (물론 @Setter도 있다) @RequiredArgsConstructor는 필요한 변수들, 즉 final이나 @NotNull이 붙은 변수들 등을 포함한 생성자를 자동생성한다.
위와 같은 방법으로 테스트 코드 파일을 생성하고 다음과 같이 추가했다.
class HelloResponseDtoTest {
@Test
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);
}
}
가장 눈에 띄는 것은 given, when, then이다. 각각 비교할 데이터 준비, 테스트하기, 예상과 같은지 비교 정도로 알아두자. 이런 식으로 하면 체계적이다.
눈여겨봐야 할 함수는 assertThat이다. 이는 assertj의 메소드를 static import한 것이다. 추가적인 라이브러리가 불필요하고 자동완성이 더 지원된다는 점에서 Junit의 그것보다 좋다.
//assertThat을 사용한 경우
assertThat(dto.getName()).isEqualTo(name);
//assertThat을 사용하지 않은 경우
if (dto.getName().equals(name) == false) {
//예외 처리
}
위 코드를 보면, 밑의 if문을 사용했을 때보다 assertThat을 사용했을 때가 더 알아보기도 쉽고 간편하다.
이제 dto를 사용하는 것도 Controller에 추가해보자.
//HelloController 에 추가한다
@GetMapping("/hello/dto")
public HelloResponseDto helloDto(@RequestParam("name") String name,
@RequestParam("amount") int amount) {
return new HelloResponseDto(name, amount);
}
또한 이에 대한 테스트도 테스트 코드를 추가한다.
//HelloControllerTest에 추가한다
@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)));
}
성공하는 것을 볼 수 있다.
'스프링부트와 AWS로 혼자 구현하는 웹 서비스' 카테고리의 다른 글
08장 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 - EC2 서버에 프로젝트를 배포해 보자 (0) | 2023.02.10 |
---|---|
06,07장 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 - AWS 서버 와 데이터베이스 환경을 만들어보자 - AWS EC2, RDS (0) | 2023.02.03 |
03장 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 - 스프링 부트에서 JPA로 데이터베이스 다뤄보자 (0) | 2023.01.20 |
01장 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 - 인텔리제이로 스프링 부트 시작하기 (0) | 2023.01.13 |