이 글은 책 「스프링 부트와 AWS로 혼자 구현하는 웹 서비스」를 공부하고 정리한 글입니다.
스프링 부트로 웹 서비스를 만들기 위한 개발 도구로 인텔리제이를 사용하도록 하겠다.
Git
)에 비해 훨씬 높은 자유도💡 책에서는
스프링 이니셜라이저
를 이용하여 프로젝트를 생성하지 않았지만, 평소에 스프링 이니셜라이저를 사용하여 개발을 해왔고 여러 에러를 해결하는 시간을 줄이기 위해서 그냥 스프링 이니셜라이저를 이용해서 생성하였다.
📌 이번 게시물에서는 TDD가 아닌 테스트 코드에 대해 배운다.
테스트 코드를 먼저 배운 뒤, TDD를 배워 보는 것을 추천한다.
위키피디아에서 말하는 테스트 코드 작성의 이점은 다음과 같다.
이 책의 저자는 테스트 코드의 이점을 다음과 같이 정리하였다.
1. 빠른 피드백
2. System.out.println()을 통해 눈으로 검증해야 하는 문제
3. 개발자가 만든 기능을 안전하게 보호해준다.
가장 대중적인 테스트 프레임워크로는 xUnit
이 있는데, 이는 개발환경x
에 따라 테스트를 도와주는 도구이다. 대표적인 xUnit
프레임워크들은 다음과 같다.
Spring 개발을 위해 이 중에서 JUnit
을 사용한다.
JUnit
은 버전 5까지 나왔지만, 아직 많은 회사에서 JUnit4
를 사용하기 때문에 JUnit4
를 사용할 것이다.
Application
클래스는 앞으로 만들 프로젝트의 메인 클래스가 된다.@SpringBootApplication
으로 인해 스프링 부트의 자동 설정, 스프링 Bean 읽기와 생성 모두 자동으로 설정된다. @SpringBootApplcation
이 있는 위치부터 설정을 읽어가기 때문에 이 클래스는 항상 프로젝트 최상단에 위치해야만 한다.SpringApplication.run
으로 인해 내장 WAS를 실행한다.Jar 파일(실행 가능한 Java 패키징 파일)
로 실행하면 된다.📌 참고 | 내장 WAS, 외장 WAS
- 꼭 스프링 부트에서만 내장 WAS를 사용할 수 있는 것은 아니지만, 스프링 부트에서는 내장 WAS를 사용하는 것을 권장하고 있다. “언제 어디서나 같은 환경에서 스프링 부트를 배포”할 수 있기 때문이다.
- 외장 WAS를 쓴다고 하면 모든 서버는 WAS의 종류와 버전, 설정을 일치시켜야만 한다. 새로운 서버가 추가되면 모든 서버가 같은 WAS 환경을 구축해야만 한다. 하지만 이렇게 내장 WAS를 사용할 경우 실수할까봐 걱정할 필요가 없고 시간이 많이 드는 문제도 해결할 수 있다.
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
}
@RestController
@ResponseBody
를 각 메소드마다 선언했던 것을 한번에 사용할 수 있게 해준다고 생각하면 된다.@GetMapping
→ 이제 /hello
로 요청이 오면 문자열 hello
를 반환하는 기능을 갖게 되었다.
@RunWith(SpringRunner.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));
}
}
@RunWith(SpringRunner.class)
@WebMvcTest
Web(Spring MVC)
에 집중할 수 있는 어노테이션@Controller
, @ControllerAdvice
등을 사용할 수 있다.@Service
, @Component
, @Repository
등은 사용할 수 없다.@Autowired
Bean
)을 주입 받는다.private MockMvc mvc
mvc.perform(get("/hello"))
/hello
주소로 HTTP GET 요청을 한다..andExpect(status().isOf())
mvc.perform
의 결과를 검증한다..andExpect(content().string(hello))
mvc.perfomr
의 결과를 검증한다."hello"
를 리턴하기 때문에 이 값이 맞는지 검증한다.localhost:8080/hello
로 접속한 결과
자바 개발자들의 필수 라이브러리 Lombok!
롬복은 자바 개발할 때 자주 사용하는 코드 Getter, Setter, 기본생성자, toString 등을 어노테이션으로 자동으로 생성해준다.
build.gradle에 아래 코드를 추가해주고, lombok 플러그인을 추가해주면 롬복을 사용할 수 있게 된다.
dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
}
기존 코드를 롬복으로 변경해보자!
web 패키지에 dto 패키지를 추가한 뒤, HelloResponseDto
를 생성하자.
package com.yeonju.book.web.dto;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public class HelloResponseDto {
private final String name;
private final int amount;
}
@Getter
@RequiredArgsConstructor
이 Dto에 적용된 롬복이 잘 작동하는지 간단한 테스트 코드를 작성해보자.
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
assertj
의 동등 비교 메소드이다.assertThat
에 있는 값과 isEqualTo
의 값을 비교해서 같을 때만 성공이다.💡 참고 | Junit과 비교하여 assertj의 장점
- CoreMatchers와 달리 추가적으로 라이브러리가 필요하지 않다.
- Junit의 assertThat을 쓰게 되면 is()와 같이 CoreMatchers 라이브러리가 필요하다.
- 자동완성이 좀 더 확실하게 지원된다.
- IDE에서는 CoreMatchers와 같은 Matchers 라이브러리의 자동완성 지원이 약하다.
테스트 실행 결과
HelloController에 새로 만든 ResponseDto를 사용하도록 코드를 추가해보자
@RestController
public class HelloController {
...
@GetMapping("/hello/dto")
public HelloResponseDto helloDto(@RequestParam("name") String name,
@RequestParam("amount") int amount) {
return new HelloResponseDto(name, amount);
}
}
@RequestParam
name
(=@RequestParam("name")
에서의 name
)이란 이름으로 넘긴 파라미터를 메소드 파라미터 name
(=String name
에서의 name
)에 저장하게 된다.name
과 amount
는 API를 호출하는 곳에서 넘겨준 값들이다. 추가된 API를 테스트하는 코드를 HelloControllerTest
에 추가한다.
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = HelloController.class)
class 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)));
}
}
param
jsonPath
$
을 기준으로 필드명을 명시한다.name
과 amount
를 검증하니 $.name
, $.amount
로 검증한다.테스트 실행 결과