Discover us

About us

Projects

Blog

Events

Members

Development Blog

GDGoC CAU 개발자와 디자이너의 작업 과정과
결과물을 공유하는 공간입니다.

어떻게 프로젝트를 시작하게 되었고,
진행하면서 느낀 개발자와 디자이너의
생생한 스토리를 직접 확인해보세요!

Development

2주차 Spring Study

  • #Back-End
  • Yejin Jang
  • 2023. 11. 28.

2주차 Spring Study

 

스터디 날짜 및 장소

  • 매주 화요일 9시 - 10시 30분
  • 208관 6층 팀플실4
 

지난주 스터디

  • 인텔리제이 설치
  • 인텔리제이에서 프로젝트 생성
  • 깃 연결
  • 객체지향 프로그래밍(OOP)
 

스터디 내용

 
테스트 코드 작성
  • 테스트 코드 없이 개발하는 경우
      1. 코드 작성
      1. 프로그램 실행
      1. API 테스트 도구로 HTTP 요청
      1. 요청결과를 System.out.println()으로 검증
      1. 결과가 다르면 프로그램 중지하고 코드 수정
      → 2~5번 과정을 코드 수정할 때마다 반복
       
       
  • 테스트 코드의 장점
    • 개발 초기 단계에 문제 발견 가능
    • 나중에 코드 리팩토링 또는 라이브러리 업그레이드 등에서 기존 기능이 올바르게 작동하는지 확인 가능
    • 기능에 대한 불확실성 감소
    • 시스템에 대한 실제 문서 제공
    •  
  • xUnit
    • 테스트 코드 작성을 도와주는 가장 대중적인 프레임워크
    • JUnit - Java
    • DBUnit - DB
    • CppUnit - C++
    • NUnit - .net
    •  
       
  • 간단한 API 생성
    • DemoApplication.java
package com.example.demo.web; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
 
  • @SpringBootApplication
    • 스프링 부트의 자동설정, 스트링 Bean 읽기와 생성을 자동으로 설정
      이 위치부터 설정을 읽기 때문에 이 클래스는 항상 프로젝트의 최상단에 위치
       
  • SpringApplication.run()
    • 내장 AWS 실행하여 같은 환경에서 스프링부트를 배포할 수 있게 한다.
       
      src>main>java>com.example.demo>web>HelloController.java 생성
package com.example.demo.web.web; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/hello") public String hello(){ return "hello"; } }
  • @RestController
    • 컨트롤러를 JSON으로 반환하는 컨트롤러로 만들어준다.
       
  • @GetMapping
    • Get 요청을 받을 수 있는 API를 만들어준다.
 
 
 
test>DemoApplicationTests.java 생성
package com.example.demo.web; import com.example.demo.web.web.HelloController; import org.junit.jupiter.api.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.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @RunWith(SpringRunner.class) @WebMvcTest(controllers = HelloController.class) public class DemoApplicationTests { @Autowired private MockMvc mvc; @Test public void return_hello() throws Exception{ String hello = "hello"; mvc.perform(get("/hello")) .andExpect(status().isOk()) .andExpect(content().string(hello)); } }
  • @RunWith(SpringRunner.class)
    • 테스트 시 JUnit에 내장된 것 외에 다른 실행자를 실행
      스프링부트 테스트와 JUnit 사이의 연결자 역할
       
  • @WebMvcTest
    • 컨트롤러 계층 만을 슬라이스 테스트할 수 있도록 도와주는 어노테이션
 
  • @Autowired
    • 스프링이 관리하는 Bean을 주입받는다.
 
  • private MockMvc mvc
    • 웹 API를 테스트할 때 사용
 
  • mvc.perform(get(”/hello”))
    • MockMvc를 통해 /hello 주소로 HTTP GET 요청
 
  • .andExpect(status().isOk())
    • mvc.perform의 결과 검증
      HTTP Header의 Status 검증
       
  • .andExpect(content().string(hello))
    • mvc.perform의 결과 검증
      응답 본문의 내용 검증
      Controller에서 반환하는 “hello” 값이 맞는지 검증
       
 
롬복 설치 및 코드 전환
  • 롬복
    • Java를 개발할 때 자주 사용하는 코드를 어노테이션으로 자동 생성해준다.
      ex) getter, setter, 기본생성자, toString 등
 
  • 롬복 설치
    • File>Settings>Plugins>Lombok 설치
      build.gradle의 dependencies에 아래 코드 추가
      dependencies{ implementation('org.projectlombok:lombok') annotationProcessor('org.projectlombok:lombok') testImplementation('org.projectlombok:lombok') testAnnotationProcessor('org.projectlombok:lombok') }
 
 
  • HelloController 코드를 롬복으로 전환
    •  
      롬복으로 변경했을 때 문제가 생기는지 테스트 코드를 돌려보면 알 수 있다.
       
    • 문제 발생 여부 확인하는 코드
    • src>main>java>com.example.demo>web>dto 패키지생성>HelloResponseDto.java 생성
      package com.example.demo.web.web.dto; import lombok.Getter; import lombok.RequiredArgsConstructor; @Getter @RequiredArgsConstructor public class HelloResponseDto { private final String name; private final int amount; }
    • @Getter
      • 선언된 모든 필드의 get메소드를 생성
         
    • @RequiredArgsConstructor
      • 선언된 모든 final 필드가 포함된 생성자를 생성
        final이 없는 필드는 생성자에 포함되지 않는다.
         
      test>java>com.example.demo>dto패키지 생성>HelloResponseDtoTest.java 생성
      package com.example.demo.web.dto; import com.example.demo.web.web.dto.HelloResponseDto; import org.junit.jupiter.api.Test; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; public class HelloResponseDtoTest { @Test public void lombokTest(){ String name = "test"; int amount = 1000; HelloResponseDto dto = new HelloResponseDto(name,amount); assertThat(dto.getName()).isEqualTo(name); assertThat(dto.getAmount()).isEqualTo(amount); } }
    • assertThat
      • assertj라는 테스트 검증 라이브러리의 검증 메소드
        검증하고 싶은 대상을 메소드 인자로 받는다.
       
    • HelloController에도 새로 만든 ResponseDto를 사용할 수 있도록 코드 추가
      • HelloController.java
        package com.example.demo.web.web; import com.example.demo.web.web.dto.HelloResponseDto; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/hello") public String hello(){ return "hello"; } @GetMapping("/hello/dto") public HelloResponseDto helloDto(@RequestParam("name") String name, @RequestParam("amount") int amount) { return new HelloResponseDto(name, amount); } }
       
       
      HelloControllerTest.java
      package com.example.demo.web; import org.junit.jupiter.api.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.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @RunWith(SpringRunner.class) @WebMvcTest public class HelloControllerTest { @Autowired private MockMvc mvc; @Test public void return_hello() throws Exception{ String hello = "hello"; mvc.perform(get("/hello")) .andExpect(status().isOk()) .andExpect(content().string(hello)); } @Test public void return_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
      • API 테스트 시 사용될 요청 파라미터 설정
        값은 String만 허용
         
    • jsonPath
      • JSON 응답값을 필드별로 검증할 수 있는 메소드
        “$”를 기준으로 필드명 명시
         
        해당 코드를 실행하면 JSON이 리턴되는 API도 정상적으로 테스트 통과하는 것을 확인할 수 있다.