2-1 스프링 부트에서 테스트 코드를 작성하자


대부분의 서비스 회사가 테스트 코드에 관해 요구하고 있습니다. 실제로 요즘 뜨고 있는 모 서비스 회사의 경우 코딩 테스트를 알고리즘이 아닌 프로젝트를 만들고, 단위테스트를 필수조건으로 두었습니다. 

TDD와 단위테스트는 다른 이야기입니다. TDD는 테스트가 주도하는 개발을 이야기합니다. 테스트 코드를 먼저 작성하는 것부터 시작합니다. 반면 다위 테스트는 TDD의 첫번째 단계인 기능 단위의 테스트코드를 작성하는 것을 이야기합니다.  이 책에서는 TDD가 아닌 단위테스트코드를 다루고 있습니다. 아래 링크의 블로그에서는 짧게 TDD에 대해서 설명합니다. 글을 읽기전 보고 오는 것도 아니면 시간이되면 보면 좋은 지식을 쌓을 것 같습니다.

 

TDD(Test-Driven Development)란?

1. TDD란? TDD(Test-Driven Development)는 말 그대로 "테스트 주도 개발: 테스트가 개발을 이끌어 나간다."라고 정의할 수 있다. 메소드 나 함수 같은 프로그램 모듈을 작성할 때 ‘작성 종료조건을 먼저

hyem-study.tistory.com

 

2.2 Hello Controller 테스트 코드 작성하기


gradle > dependencies 에 아래 코드를 추가합니다. 

implementation 'junit:junit:4.13.1'

 

java 디렉토리를 마우스 오른쪽 버튼을 클릭하여 [new -> package]를 차례로 선택해서 생성합니다. 일반적으로 패키지명 은 웹사이트 주소의 역순으로 합니다. 저는 무슨연습을 하였는지 알기위해 프로젝트명에 연습한 기술 내용를 적습니다. 하지만 최대한 책의 내용과 같게하기위해 패키지명은 같게 했습니다. 패키지 생성 후 패키지 하위에 javaClass 생성합니다.

패키지명 : com.jojoIdu.book  

클래스 명 : Application

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

Application.java 클래스는 앞으로 만들 프로젝트의 메인 클래스가 됩니다.

@SpringBootAppliction - 스프링부트의 자동 설정, 스프링 Bean읽기와 생성을 모두 자동으로 설정됩니다. 

main() - 메소드를 실행하는 SpringApplication.run  으로 인해 내장 WAS가 실행됩니다.

그 다음으로는  만든 패키지 하위에 web이라는 패키지명으로 생성하고 컨트롤러와 관련된 클래스들은 모두 이 패키지에 담겠습니다. 테스트 해볼 컨트롤러를 만들어 보겠습니다. web하위에 클래스명 HelloController 생성합니다.

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }

}

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

@GetMapping - HTTP Method인 GET요청을 받을 수 잇는 API를 만들어 줍니다.

src/test/java/com/jojoldu/book/springboot/HelloControllerTest.java

@RunWith(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));
    }
}

1. @RunWith(SpringRunner.class) - 테스트를 진행할 때 JUnit에 내장된 실행자 외에 다른 실행자를 실행시킵니다. 여긴서는 SpringRunner라는 스프링실행자를 사용합니다. 즉 스프링 부트 테스트와 Junit 사이에 연결자 역활을 합니다.

2. @WebMvcTest - 여러 스프링테스트 어노테이션 중 Web(Spring MVC)에 집중할 수 있는 어노테이션 입니다.  선언 할 경우 @Controller @ControllerAdvice등을 사용할 수 있습니다. 단 @Service @Component @Repository를 사용할 수 없습니다. 여기서는 컨트롤러만 사용하기 때문에 선언합니다.

3. private MockMvc mvc - 웹 API를 테스트할 때 사용합니다. 스프링 MVC 테스트의 시작점입니다.

4. mvc.perform(get("/hello)) - MockMvc 를 통해 특정주소로 HTTP GET요청을 합니다. 체이닝하여 아래와 같은 여러 검증 기능을 이어서 사용가능합니다.

5. andExpect(Status().isOk()) - mvc.perform의 결과를 검증합니다. HTTP Header의 Status를 검증합니다. 여기선 200인지를 확인합니다.

6. andExpect(content().string(hello)) - mvc.perform의 결과를 검증합니다. 리턴값이 맞는지 체크합니다.

아래 사진처럼 실행은 메소드 옆에 초록색 화살표로 실행한다.

통과된 이미지

2.3 롬복 소개 및 설치하기


1. bulid.gradle에 다음 코드를 추가해주세요

implementation('org.projectlombok:lombok')

2. ctrl + shift + a  > action > plugin 검색하여 엔터누르면 팝업이 뜨고 marketplace 에서 lombok 검색 후 설치 해준다.설치가 완료 되면 Restart IDE를 클릭해서 재시작하면 하단 오른쪽에 팝업에 롬복에대한 설정이 필요하다고 등장합니다. 설정해야 할 장소를 알려주는데 파란색으로 표기된 곳을 클릭합니다.

3. 마지막으로 Enable Annotation processting을 체크합니다. 

혹시 3번을 체크해도 lombok 어노테이션이 먹지 않는다면  build.gradle > dependencies에 아래 코드를 추가해보세요 저도 어노테이션이 안먹혀서 이것저것 해보니 알게되었습니다.

annotationProcessor 'org.projectlombok:lombok'

 

 2.4 Hello COntroller 코드를 롬복으로 전환하기


1. com.jojoldu.book.springboot.web 패키지 하위에 dto 패키를 생성

2. 그 하위에 HelloResponseDto 생성

@Getter
@RequiredArgsConstructor
public class HelloResponseDto {

    private final String name;
    private final int amount;

}

@Gettet - 선언된 모든 필드의 get메소드를 생성해 줍니다.

@RequiredArgsConstructor - 선언된 모든 final 필드가 포함된 생성자를 생성해줍니다. final이 없는 필드는 생성자에 포합 되지 않습니다.

3. src/test/java/com/jojoldu/book/springboot/web/dto/HelloResponesDtoTest.java 생성

public 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 - assertjd의 동등 비교 메소드 입니다.

테스트 해보면 성공한 걸 알 수 있습니다. 혹시 성공하지 못했다면 오래 걸리더라도 어디가 잘못 되었는지 확인해보세요 저도 처음에 안되었는데 잘못된 곳이 있더라고요. 

테스트로 인해 검증된 사실

  • @Getter 롬복어노테이션으로 getter와 @RequiredArgsConstructor 으로 생성자가 자동으로 생성 된것이 증명되었습니다.

4. HelloController에 새로 만든 ResponseDto를 사용합니다.

@GetMapping("/hello/dto")
public HelloResponseDto helloDto(@RequestParam("name") String name,
                                 @RequestParam("amount") int amount) {
    return new HelloResponseDto(name, amount);
}

5. HelloControllerTest에 test를 추가합니다.

@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)));
}

jsonPath - JSON 응답값을 필드별로 검증할 수 있는 메소드입니다. $를 기준으로 필드명을 명시합니다.

6. 테스트가 성공하는지 확인합니다. 성공하지못한다면 콘솔을 확인하고 수정 후 반복합니다.

복사했습니다!