BOOK 2 - 스프링부트와 AWS로 혼자 구현하는 웹 서비스(1)
스프링부트와 AWS로 혼자 구현하는 웹 서비스 - 1
프로젝트 생성 및 초기 설정
gradle - java 프로젝트 생성
-
groupId,artifactId설정 -
프로젝트 생성 직후
build.gradle파일 상태plugins { id 'java' } group 'com.hs' version '1.0-SNAPSHOT' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' } -
build.gradle상단에 프로젝트 플러그인 의존성 관리를 위한 코드 추가buildscript { ext { springBootVersion = '2.2.4.RELEASE' } repositories { mavenCentral() jcenter() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } }ext:build.gradle에서 사용하는 전역변수 설정repositories: 각종 의존성(라이브러리)들을 어떤 원격 저장소에서 받을지 설정- 기본적으로
mavenCentral을 많이 사용하지만 직접 만든 라이브러리의 간단한 업로드를 지원하는jcenter도 최근에 많이 사용하고 있다.
- 기본적으로
- spring boot 관련 라이브러리들의 버전 관리를 한 곳에 집중함으로써 버전 충돌 문제를 해결할 수 있다.
-
앞에서 선언한 플러그인 의존성들을 적용할 것인지 결정하는 코드 추가
apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management'io.spring.dependency-management: 스프링부트의 의존성을 관리해주는 플러그인이기 때문에 필수적으로 추가
-
프로젝트 개발에 필요한 의존성 선언
dependencies { compile('org.springframework.boot:spring-boot-starter-web') testCompile('org.springframework.boot:spring-boot-starter-test') }- 여기서는 버전을 명시하지 않아야 위에서 선언한
springBootVersion의 버전을 따라가게 된다. (버전 관리를 집중하기 위함)
- 여기서는 버전을 명시하지 않아야 위에서 선언한
-
build.gradle의 변경사항 import 후 우측 gradle 탭에서 import 된 dependency 확인할 수 있다.
Git 연결
-
.gitignore파일 생성- 특정 파일 혹은 디렉토리를 git의 관리 대상에서 제외할 때 사용
# Eclipse .DS_STORE .classpath .settings/ .project # Intellij .idea/ *.iml *.ipr *.iws out/ # Mac .DS_Store # Gradle .gradle/ log/ build/ # Java *.class #classes classes/.idea/: 인텔리제이에서 프로젝트 실행시 자동으로 생성되는 파일.class:.java파일을 컴파일했을 때 생성되는 파일
SpringBootApplication 생성 및 기본 Controller 생성
SpringBootApplication 생성
package com.hs.all.review;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AllReviewApplication {
public static void main(String[] args) {
SpringApplication.run(AllReviewApplication.class, args);
}
}
- 프로젝트의 메인 클래스
@SpringBootApplication: 스프링 부트의 자동 설정, 스프링 bean 관리가 자동으로 설정된다.- 해당 annotation이 있는 위치부터 설정을 읽어가기 때문에 항상 프로젝트의 최상단에 위치해야 한다.
SpringApplication.run: 내장 WAS 실행- 내장 WAS를 사용하는 이점 : 언제 어디서나 같은 환경에서 스프링 부트를 배포할 수 있다.
- 즉, 스프링 부트로 만들어진 JAR 파일만 있으면 같은 환경의 서버를 구성할 수 있다.
- 내장 WAS를 사용하는 이점 : 언제 어디서나 같은 환경에서 스프링 부트를 배포할 수 있다.
HelloController 생성
-
어플리케이션의 기본적인 동작(서버 작동)을 테스트 하기 위해 기본 controller를 생성한다.
@RestController public class HelloController { @RequestMapping("/hello") public String hello() { return "hello all-review"; } }@RestController: 해당 클래스를 JSON을 반환하는 컨트롤러로 만들어주는 annotation/hello로 요청이 들어왔을 때 문자열hello all-review를 반환하는 기능을 가지게 된다.
-
브라우저로 해당 요청이 잘 동작하는지 테스트한다.

HelloController Test Code 작성
HelloController의 동작을 테스트 하기 위한 테스트 코드를 작성한다.- WAS를 실행하지 않고 해당 코드가 잘 동작하는지 테스트 할 수 있다.
단위 테스트
-
TDD와 단위 테스트는 다르다.
-
TDD는 테스트가 주도하는 개발로써, 테스트 코드를 먼저 작성하고, 테스트 코드를 통과하는 코드를 작성하는 방법론을 말한다.
-
단위 테스트는 TDD의 첫번째 단계인
기능 단위의 테스트 코드를 작성하는 것을 말한다.
-
-
단위 테스트는 개발단계 초기에 문제를 발견하게 도와주어 기능에 대한 불확실성을 감소시킨다.
- 또한, 코드를 리팩토링하거나 라이브러리 업그레이드 등을 할 때 기존 기능이 올바르게 동작하는지 확인할 수 있다.
-
단위 테스트는 코드를 작성하고 WAS를 직접 실행시킨 뒤, API 테스트 도구로 HTTP 요청을 하고 요청 결과를 직접 눈으로 확인하는 복잡한 과정을 반복하지 않아도 빠르게 코드를 검증할 수 있다.
-
테스트 코드는 기존 기능이 잘 작동되는 것을 보장해주는 의미이다.
HelloControllerTest
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = HelloController.class)
public class HelloControllerTest {
@Autowired
private MockMvc mvc;
@Test
public void return_hello_with_get_request() throws Exception {
String expected = "hello all-review";
mvc.perform(MockMvcRequestBuilders.get("/hello"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string(expected));
}
}
@RunWith(SpringRunner.class)- 테스트를 진행할 때 JUnit에 내장된 실행자 외에 다른 실행자(여기서는
SpringRunner)를 실행시킨다. - 즉, 스프링 부트 테스트와 JUnit 사이에 연결자 역할을 한다.
- 테스트를 진행할 때 JUnit에 내장된 실행자 외에 다른 실행자(여기서는
@WebMvcTest- 여러 스프링 테스트 어노테이션 중 Web(Spring MVC)에 집중할 수 있는 어노테이션
@Controller,@ControllerAdvice등을 사용할 수 있고,@Service나@Component,@Repository등은 사용할 수 없다.
-
MockMvc: 웹 API를 테스트할 때 사용하고, 이 클래스를 통해 HTTPGET,POST등에 대한 API 테스트를 할 수 있다. mvc.perform(MockMvcRequestBuilders.get("/hello"))MockMvc를 통해/hello라는 주소로 HTTP GET 요청을 한다.- chaining이 지원되어 여러 검증 기능을 이어서 선언할 수 있다.
andExpect(...):mvc.perform의 결과를 검증한다.
Lombok library 설치
-
프로젝트에 롬복 라이브러리 추가
build.gradle에 롬복 등록
compile('org.projectlombok:lombok') -
롬복 플러그인 설치
- 롬복 플러그인은 인텔리제이 사용시 최초 한번만 설치하면 모든 프로젝트에서 사용 가능하다.
-
Enable annotation processing체크- 해당 프로젝트의
preferences창에서 annotation 설정이 가능하도록 체크해준다. - 각 프로젝트마다 따로 설정해 주어야 한다.

- 해당 프로젝트의
HelloResponseDto 생성
HelloController에서 응답으로 넘겨줄 DTO를 생성한다.
@Getter
@AllArgsConstructor
public class HelloResponseDto {
private String name;
private int amount;
}
@Getter: 선언된 모든 필드의 get 메서드 생성@AllArgsConstructor: 선언된 모든 필드가 포함된 생성자 생성
HelloResponseDto Test Code 작성
public class HelloResponseDtoTest {
@Test
public void test_hello_response_dto() {
// 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);
}
}
assertThatassertj라는 테스트 검증 라이브러리의 검증 메서드- 검증하고 싶은 대상을 메서드 파라미터로 넘겨준다.
- method chaining이 지원되어
isEqualTo와 같이 메서드를 이어서 사용할 수 있다.
isEqualToassertj라이브러리의 동등 비교 메서드- 비교하고 싶은 대상을 메서드 파라미터로 넘겨주어 검증 대상과 값이 같을 때만 테스트 성공
Junit의assertThat보다assertj를 사용하는 이유Junit의assertThat은is()와 같이CoreMatchers라이브러리를 추가적으로 사용해야 한다.- 그에 비해
assertj의assertThat은 추가 라이브러리를 필요로 하지 않는다.
HelloController에 HelloResponseDto를 리턴하는 메서드 추가
-
HelloController에/hello/dtourl을 가지는GET메서드 추가@GetMapping("/hello/dto") public HelloResponseDto helloDto(@RequestParam String name, @RequestParam int amount) { return new HelloResponseDto(name, amount); }@RequestParam: 외부에서 API로 넘긴 파라미터를 가져오는 annotation
-
HelloControllerTest에 추가된 메서드의 테스트 코드 추가@Test public void return_hello_dto_with_get_request() throws Exception { String name = "test"; int amount = 1000; mvc.perform(MockMvcRequestBuilders.get("/hello/dto") .param("name", name) .param("amount", String.valueOf(amount))) .andExpect(status().isOk()) .andExpect(jsonPath("$.name", Matchers.is(name))) .andExpect(jsonPath("$.amount", Matchers.is(amount))); }param- API 테스트 실행 시 사용될 요청 파라미터를 설정한다.
String타입만 가능하므로 숫자, 날짜 등의 데이터를 설정할 때에는 포맷팅을 해주어야 한다.
jsonPath- JSON 응답값을 필드별로 검증할 수 있는 메서드
$를 기준으로 필드명을 명시한다.