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 확인할 수 있다.

    image

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 파일만 있으면 같은 환경의 서버를 구성할 수 있다.

HelloController 생성

  • 어플리케이션의 기본적인 동작(서버 작동)을 테스트 하기 위해 기본 controller를 생성한다.

    @RestController
    public class HelloController {
      
        @RequestMapping("/hello")
        public String hello() {
            return "hello all-review";
        }
    }
    
    • @RestController : 해당 클래스를 JSON을 반환하는 컨트롤러로 만들어주는 annotation
    • /hello 로 요청이 들어왔을 때 문자열 hello all-review 를 반환하는 기능을 가지게 된다.
  • 브라우저로 해당 요청이 잘 동작하는지 테스트한다.

    image

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 사이에 연결자 역할을 한다.
  • @WebMvcTest
    • 여러 스프링 테스트 어노테이션 중 Web(Spring MVC)에 집중할 수 있는 어노테이션
    • @Controller , @ControllerAdvice 등을 사용할 수 있고, @Service@Component , @Repository 등은 사용할 수 없다.
  • MockMvc : 웹 API를 테스트할 때 사용하고, 이 클래스를 통해 HTTP GET , 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 설정이 가능하도록 체크해준다.
    • 각 프로젝트마다 따로 설정해 주어야 한다.

    image

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);
  }
}
  • assertThat
    • assertj 라는 테스트 검증 라이브러리의 검증 메서드
    • 검증하고 싶은 대상을 메서드 파라미터로 넘겨준다.
    • method chaining이 지원되어 isEqualTo 와 같이 메서드를 이어서 사용할 수 있다.
  • isEqualTo
    • assertj 라이브러리의 동등 비교 메서드
    • 비교하고 싶은 대상을 메서드 파라미터로 넘겨주어 검증 대상과 값이 같을 때만 테스트 성공
  • JunitassertThat 보다 assertj 를 사용하는 이유
    • JunitassertThatis() 와 같이 CoreMatchers 라이브러리를 추가적으로 사용해야 한다.
    • 그에 비해 assertjassertThat 은 추가 라이브러리를 필요로 하지 않는다.

HelloController에 HelloResponseDto를 리턴하는 메서드 추가

  • HelloController/hello/dto url을 가지는 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 응답값을 필드별로 검증할 수 있는 메서드
      • $ 를 기준으로 필드명을 명시한다.