No sweet without sweat

[DAY 3] SpringBoot, AWS로 웹서비스 구현 <TOD, 단위테스트 차이, API작성> 본문

SpringBoot + AWS 프로젝트

[DAY 3] SpringBoot, AWS로 웹서비스 구현 <TOD, 단위테스트 차이, API작성>

Remi 2022. 4. 24. 20:23
728x90
반응형

많은 서비스 회세어서 테스트 코드에 요구를 하고 있음.

▶ 테스트 코드

- TDD == 단위 테스트(Unit Test) → X

=> TDD와 단테는 다른 이야기입니다.

1. TDD

- TDD는 테스트가 주도하는 개발입니다.

- 테스트 코드를 먼저 작성

1. 항상 실패하는 테스트를 먼저 작성하고(RED)

2. 테스트가 통과하는 프로덕션 코드를 작성하고(GREEN)

3. 테스트가 통과하면 프로덕션 코드를 리팩토링합니다.(Refactor)

2. 단위 테스트

1) 기능 단위의 테스트 코드를 작성

- TDD와 달리 테스트 코드를 꼭 먼저 수행하는 것도 아니고 리팩토링도 포함X

=> 순수하게 테스트코드만 작성

* TDD를 배워보고 싶으신분은 여기로.

https://repo.yona.io/doortts/blog/issue/1

2) 단위테스트 장점

1. 가장 먼저 빠른 피드백

2. 테스트 코드를 작성하면 더는 사람이 눈으로 검증할 필요 X => 자동검증

3. 개발자가 만든 기능을 보호

=> 새로운 기능이 추가될 때, 기존 기능이 잘 작동되는 것을 보장

그외 위키백과 참조했으며, 내용은 다음 아래와 같습니다.

문제점 발견[편집]
유닛 테스트의 목적은 프로그램의 각 부분을 고립 시켜서 각각의 부분이 정확하게 동작하는지 확인하는 것이다. 즉, 프로그램을 작은 단위로 쪼개서 각 단위가 정확하게 동작하는지 검사하고 이를 통해 문제 발생 시 정확하게 어느 부분이 잘못되었는지를 재빨리 확인할 수 있게 해준다. 따라서 프로그램의 안정성이 높아진다. 유닛 테스트는 일견 개발 시간을 증가 시키는 것처럼 보이지만 개발 기간 중 대부분을 차지하는 디버깅 시간을 단축시킴으로써 여유로운 프로그래밍을 가능케 한다.
변경이 쉽다[편집]
프로그래머는 언제라도 유닛 테스트를 믿고 리팩토링을 할 수 있다. 리팩토링 후에도 해당 모듈이 의도대로 작동하고 있음을 유닛 테스트를 통해서 확신할 수 있다. 이를 회귀 테스트(Regression testing)라 한다. 어떻게 코드를 고치더라도 문제점을 금방 파악할 수 있고 수정된 코드가 정확하게 동작하는지 쉽게 알 수 있게 되므로 프로그래머들은 더욱 더 의욕적으로 코드를 변경할 수 있게 된다. 좋은 유닛 테스트 디자인은 그 유닛이 사용되는 모든 경로를 커버할 수 있는 테스트 케이스를 만들어 준다.
지속적인 유닛 테스트 환경을 구축하면 어떠한 변화가 있더라도 코드와 그 실행이 의도대로 인지를 확인하고 검증 할 수 있게 된다. 확립된 개발 방법과 유닛 테스트의 범위에 따라서 프로그램의 정확성이 좌우된다.
통합이 간단하다[편집]
유닛 테스트는 유닛 자체의 불확실성을 제거해주므로 상향식(bottom-up) 테스트 방식에서 유용하다. 먼저 프로그램의 각 부분을 검증하고 그 부분들은 합쳐서 다시 검증하는 통합 테스트에서 더욱 더 빛을 발한다.

* 테스트 코드 작성을 도와주는 프레임워크(XUnit)

1. JUnit - JAVA

2. DBUnit - DB

3. CppUnit - C++

3. NUnit - .net

저희는 자바로 개발하기에 Junit으로 사용

(JUnit4로 개발 / 최신판은 5까지 나왔으나 아직 4를 많이 이용)

실습 Hello Controller 테스터 코드 작성

1. 패키지 생성

- 저는 다음과 같이 패키지명 정의

* 일반적으로 패키지명은 웹 사이트 주소의 역순으로 한다.

2. Application 클래스 정의

package com.jojoldu.book.springboot;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

- 스프링부트의 자동 설정, 스프링 Bean 읽기와 생성을 모두 자동으로 설정 , 특히나 @SpringBootAppliaction이 있는 위치부터 설정을 읽어가기 때문에 이 클래스는 항상 프로그젝의 최상단에 위치해야 합니다.

/-main Method에서 실행하는 SpringAPplication.run으로 인해 내장 WAS를 실행

- 내장 WAS란 별도로 외부에 WAS를 두지 않고 애플리케이션을 실행할 때 내부에서 실행

- 이렇게 되면 항상 서버에 톰캣을 설치할 필요가 없게 되고, 스프링 부트로 만들어진 Jar 파일로 실행

- 스프링부트에선 내장 WAS를 사용할 수 있는 것은 아니지만, 스프링부트에서는 내장 WAS를 사용하는 것을 권장

WHY > 언제 어디서나 같은 환경에서 스프링 부트를 배포할 수 있기 때문에

3. 간단한 API 생성(HelloController)

package com.jojoldu.book.springboot.web;

import com.jojoldu.book.springboot.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";
    }
  
}

■ RestController

- 컨트롤러를 JSON을 반환하는 컨트롤러로 만들어 줍니다.

- 예전에는 @ResponseBody를 각 메소드마다 선언했던 것을 한번에 사용할 수 있게 해준다고 생각

■ GetMapping

- HTTP Method인 Get의 요청을 받을 수 있는 API를 만들어 줍니다.

■ @RequestParam

- 외부에서 API로 넘긴 파라미터를 가져오는 어노테이션

- 여기서는 외부에서 name 이란 이름으로 넘긴 파라미터를 메소드 파라미터 name에 저장하게 됨.

4. TEST 코드 작성(HelloControllerTest)

package com.jojoldu.book.springboot.web;


import org.junit.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(value = SpringRunner.class)
@WebMvcTest(controllers = HelloController.class)
public 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)

- 테스트를 진행할 때 JUnit에 내장된 실행자 외에 다른ㅅ 맇애자를 실행시킵니다.

- 여기서는 SpringRunner라는 스프링 실행자를 사용합니다.

- 즉 스프링 부트 테스트와 Junit 사이에 연결자 역할을 합니다.

■ @WebMvcTest

- 여러 스프링 테스트 어노테이션 중, Web(Spring MVC)에 집중할 수 있는 어노테이션 입니다.

- 선언할 경우 @COntroller, @ControllerAdvice 등을 사용할 수 있습니다.

- 단 @Service, @Component, @Repository 등은 사용할 수 없습니다.

- 여기서는 컨트롤러만 사용하기 떄문에 선언

■ @ Autuwired

- 스프링이 관리하는 빈(Bean)을 주입 받습니다.

■ private MockMvc mvc

- 웹 API를 테스트할 때 사용합니다.

- 스프링 MVC 테스트의 시작점입니다.

- 이 클래스를 통해 HTTP GET, POST등에 대한 API 테스트를 할 수 있습니다.

■ mvc.perform(get("/hello"))

- MockMvc를 통해 /hello 주소로 HTTP GET 요청을 합니다.

- 체이닝이 지원되어 아래와 같이 여러 검증 기능을 이어서 선언할 수 있습니다.

■.andEXpect(status().isOk())

- mvc.perform의 결과를 검증

- HTTP Header의 Status를 검증

- 우리가 흔히 알고 있는 200, 404, 500 등의 상태 검증

■ . andExpect(content().string(hello))

- mvc.perform의 결과를 검증

- 응답 본문의 내용을 검증

5. 테스트 확인

- hello가 잘 출력되는거 확인

728x90
반응형
Comments