[Spring] 스프링 부트와 AWS로 혼자 구현하는 웹 서비스2

김나윤·2024년 9월 27일
0

Spring

목록 보기
4/9

02. 스프링 부트에서 테스트 코드 작성하기

1) HelloController 테스트 코드 작성하기

견고한 서비스를 만들기 위해서는 TDD(Test Driven Development)테스트 코드가 필요하다.
TDD(Test Driven Development)와 테스트 코드는 다른 이야기이다.
먼저 TDD는 테스트가 주도하는 개발을 이야기한다.

spring initializr를 사용하였기에 자동으로 src/main/java/com/springboot/project/springboot_webservice_project/SpringbootWebserviceProjectApplication.java 경로로 SpringbootWebserviceProjectApplication 파일이 생성되어 있었다.
이름 짓기 좀 잘할 걸.. 파일명 너무 길어

이 Application 클래스가 앞으로 만들 프로젝트의 메인 클래스가 된다.

다음으로 테스트를 위한 Controller가 필요하다.
main > java 바로 하위 폴더인 src/main/java/com/springboot/project/springboot_webservice_project 에 web이란 이름의 하위 폴더를 생성한다.
그리고 앞으로 controller와 관련된 클래스들은 모두 이 패키지에 담도록 한다.
web 폴더 내부에 HelloController.java 파일을 만들고 간단한 API를 만든다.

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";
    }
}

코드를 다 작성했으면 HelloController 클래스명을 한번 클릭하고
Alt + Enter > Create Test 를 선택한다.

클래스명을 입력하고 확인을 누른다.

그러면 자동으로 source > test > java > springboot_webservice_project > web 하위에 HelloControllerTest.java 파일이 생성된다.

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
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)
@SpringBootTest
@AutoConfigureMockMvc


public class HelloControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @Test
    public void hello가_리턴된다()throws Exception{
        String hello="hello";
        mockMvc.perform(get("/hello"))
                .andExpect(status().isOk())
                .andExpect(content().string(hello));
    }
}

HelloControllerTest 파일에 다음과 같은 코드를 입력한다.

여기까지 진행했더니 HelloControllerTest 파일에 cannot resolve symbol 'test' 에러가 떴다.
구글링을 해보니 제대로 import가 되지 않아 생기는 문제라고 했고 아래 블로그에서 제시된 방법들을 모두 해보았지만 해결되지 않았다.

https://velog.io/@seowj0710/IntelliJ-cannot-resolve-symbol-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95

계속 검색하다 아래 블로그에서 같은 문제에 대한 해결방안을 알려주셔서 무사히 해결할 수 있었다.

코드도 다 작성하고 에러도 해결한 뒤, 실행만 하면 됐는데
Run이 되지 않는 문제가 또 생겼다..
구글링을 해보니 다양한 이유와 해결방법이 있었는데 나는 library를 추가했더니 문제가 해결되었다.

import org.junit.Test; 에서 Test가 빨간색이 뜨는 문제를 해결하고 난 뒤, 블로그에서 소개한 library 추가를 하지 않고 넘어갔는데 그게 문제였다.

File > Project Structure > Project Settings > Libraries > + > From Maven... 을 선택하고

org.junit.jupiter:junit-jupiter:5.4.2 를 입력한 뒤, 확인을 눌러주었더니 정상적으로 Run이 되었다.

(추가) 이후로도 프로그램을 재실행하면 계속해서 빨간색으로 오류가 떴는데, 버전이 업그레이드 되면서 달라진 부분이 있어서 그랬던 것!
저자 블로그를 참고하며 import 하는 부분과 어노테이션 부분을 수정해주니 그 이후로는 문제가 발생하지 않았다.

실행결과 Test passed: 1 이라고 뜨며 성공적으로 테스트가 완료된 것을 확인할 수 있었다.

이때 빨간색으로 WARNING이 잔뜩 떠서 오류가 생긴 건 아닌가 싶어 검색을 해보았더니 크게 문제가 없는 부분이었다.

WARNING: A Java agent has been loaded dynamically (C:\Users\user\.gradle\caches\modules-2\files-2.1\net.bytebuddy\byte-buddy-agent\1.14.11\f9cb566608fbac6bc7bf54901a7aa11543a989ee\byte-buddy-agent-1.14.11.jar)

WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning

WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information

WARNING: Dynamic loading of agents will be disallowed by default in a future release

OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

검색결과, JDK 21에 올라오면서 해당 기능이 Deprecated 되어 발생한 Warning이라 신경 쓰지 않고 사용해도 된다고 한다.

Application.java 파일로 이동해 마찬가지로 main 메소드의 왼쪽 화살표 버튼을 클릭해, 수동으로도 실행해서 정말 정상적으로 값이 출력되는지 확인해보았다.
실행해보면 테스트 메소드 실행 때와 마찬가지로 스프링 부트 로그가 보이고, 톰캣 서버 8080 포트로 실행되었다는 것도 로그에 출력되었다.

웹 브라우저에 localhost:9090/hello 를 입력해 hello가 잘 출력되는 것을 확인함으로써 테스트가 성공적으로 완료 되었음을 확인할 수 있었다.


2) 롬복(Lombok) 설치하기

롬복(Lombok)은 자바 개발자들의 필수 라이브러리로, 자바 개발할 때 자주 사용하는 코드 Getter, Setter, 기본생성자, toString 등을 어노테이션으로 자동 생성해준다고 한다.

Eclipse의 경우, 롬복 설치가 번거롭지만 IntelliJ에서는 플러그인 덕분에 쉽게 설정이 가능하다.

프로젝트에 롬복을 추가하는 방법은 간단하다.
build.gradle에

implementation('org.projectlombok:lombok')

코드만 추가해주면 된다.

그런데 책에서는 implementation 대신 compile('org.projectlombok:lombok')을 사용하고 있는데, 현재 최신 gradle 버전에서는 compile 대신 implementation을 사용한다.
책에서처럼 compile을 사용하니 아래와 같은 오류가 생겼다.

라이브러리를 다 다운 받았으면 롬복 플러그인을 설치하면 된다.
Windows 기준 Ctrl + Shift + A > plugins 검색 > Marketplace 탭 > lombok 검색 > Install

플러그인 설치가 완료되면,
Settings > Build > Compiler > Annotation Processors 에 들어가 Enable annotation processing을 체크하면 된다.

이렇게까지 했으면 롬복 사용을 위한 준비가 끝났다.

참고로 롬복은 프로젝트마다 설정해야 한다. 플러그인 설치는 한 번만 하면 되지만 buil.gradle에 라이브러리를 추가하는 것과 Enable annotation processing을 체크하는 것은 프로젝트마다 진행해야 한다.


3) HelloController 코드를 롬복으로 전환하기

그럼 기존 코드를 롬복으로 변경해보자.

web 패키지에 dto 패키지를 만들어 HelloResponseDto 파일을 만든다.

만든 HelloResponseDto.java 파일에 코드를 작성해 주고,

이 Dto에 적용된 롬복이 잘 작동하는지 간단한 테스트 코드를 작성해본다.
test > java 하위에 위의 경로대로 HelloResponseDtoTest 파일을 만들고 아래와 같이 코드를 입력해준다.

작성된 테스트 메소드를 실행해 본다.

정상적으로 실행되는 것을 확인하였다.

다음으로 HelloController에도 새로 만든 ResponseDto를 사용하도록 코드를 추가한다.

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

추가된 API를 테스트하는 코드를 HelloControllerTest에 추가한다.
그러면 HelloControllerTest 소스 코드는 아래와 같이 정리된다.

package com.springboot.project.springboot_webservice_project.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.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;


@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc


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

4) 코드 오류 해결하기

이렇게 코드도 다 잘 입력했다고 생각하고 돌려봤는데...
Test passed:0.... Failed 2.........
끝없는 오류에 기절할 뻔했지만...
여기서 포기하면 절대 발전이 없을 것 같아 구글링 하며 왜 오류가 생겼는지 찾아보았다.

▶ jsonPath(), is() 오류

jsonPaht()와 is(name)에 빨간 밑줄이 그여 있었다.

위 사이트를 참고해 문제를 해결했다.
살펴보니 import를 잘못해서 생긴 문제였다.

수동으로 import 해주니 이 문제는 쉽게 해결되었다.

▶ java.lang.AssertionError: Status, 404 Error

return_helloDto 메서드는 해결되었고 이제 return_hello만 남았다..

java.lang.AssertionError: Status
Expected :200
Actual :404

이렇게 오류가 떴는데, 먼저 java.lang.AssertionError: Status 가 무엇을 뜻하는지 찾아보았다.

(후보1) 코드에 오탈자가 있나?
=> 오타난 건 없는데..

(후보2) 파일 경로 오류?
https://ryugaram.tistory.com/24
=> 경로에는 문제가 없었다.

위 두 가지가 해당 사항이 없길래 조금 더 고민해봤는데,
404 에러는 해당 URL 에 대응되는 API 가 존재하지 않을 때 or Mapping이 되지 않을 때 발생한다고 했으니까 HelloController.java에서 @GetMapping에 뭔가 문제가 있을 것 같았다.
뭐지.. 나 매핑 잘 했지 않나...?
그래서 다시 코드를 살펴보니 역시 Mapping 문제였다.

소스 코드를 저렇게 적어놨던 것...
/hello와 Mapping 되지 않아 오류가 발생한 것이었다.

소스코드에 @GetMapping("/hello") 부분을 추가하고 다시 실행해보니 정상적으로 테스트가 실행되었다.

역시 컴퓨터는 잘못된 게 없구나

마지막으로 수많은 빨간 WARNING이 신경 쓰였는데 저번에 나왔던 주의랑 똑같았다.
JDK 21에 올라오면서 해당 기능이 Deprecated 되어 발생한 Warning으로 무시해도 상관없다고 한다.
나 역시 프로그램을 실행하는데 문제가 없어 그냥 넘어가기로 했다.

profile
Hello, world!

0개의 댓글