스터디/[스프링 부트와 AWS로 혼자 구현하는 웹 서비스] (2025.03)

[스프링 부트와 AWS로 혼자 구현하는 웹 서비스] 2장. 스프링 부트에서 테스트 코드를 작성하자

ttoance 2025. 4. 11. 10:51
반응형

 

테스트 코드 소개 

  • TDD는 단위 테스트(Unit Test)와 다른 개념이다. 
  • TDD는 테스트가 주도하는 개발을 의미한다.
    • 테스트 코드를 먼저 작성하는 것부터 시작한다. 
    • 항상 실패하는 테스트를 먼저 작성하고 (Red)
    • 테스트가 통과하는 프로덕션 코드를 작성하고 (Green) 
    • 테스트가 통과하면 프로덕션 코드를 리펙토링 한다 (Refactor)
  • 단위 테스트는 TDD의 첫번째 단계인 기능 단위의 테스트 코드를 작성하는 것을 의미한다. 
    • TDD와 달리 테스트 코드를 꼭 먼저 작성해야 하는 것도 아니고, 리펙토링도 포함되지 ㅇ낳는다. 
    • 순수하게 테스트 코드만 작성하는 것을 의미한다. 

 

테스트 코드 작성 도와주는 프레임워크 

  • 가장 대중적인 테스트 프레임워크로는 xUnit이 있다. 
    • JUnit - Java
    • DBUnit - DB
    • CppUnit - C++
    • NUnit - .net 

 

Hello Controller 테스트 코드 작성하기 

 

Application.java

package org.example;

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);
    }
}
  • @SpringBootApplication으로 인해 스프링 부트의 자동 설정, 스프링 Beans의 읽기와 생성을 모두 자동으로 설정된다. 
    • @SpringBootApplication이 있는 위치부터 설정을 읽어가기 때문에 이 클래스는 항상 프로젝트 최상단에 위치해야 한다. 
  • SpringApplication.run으로 인해 내장 WAS(Web Application Server, 웹 어플리케이션 서버)를 실행한다. 
    • 내장WAS란 별도로 외부에 WAS를 두지 않고 애플리케이션 실행할 때 내부에서 WAS를 실행하는 것을 의미한다. 
    • 이렇게 하면 항상 서버에 톰캣을 설치할 필요가 없게 되고, 스프링 부트로 만들어진 jar파일을 실행하면 된다. 
  • 내장 WAS 사용을 권장하는 이유 : 언제 어디서나 같은 환경에서 스프링 부트를 배포 할 수 있다. 
    • 외장 WAS를 쓴다 하면 모든 서버는 WAS의 종류와 버전, 설정을 일치시켜야 하기 때문에 서버가 많을 경우 운영상 어려움이 발생할 수 있다. 

 

 

 

HelloResponseDto.java

package org.example.web.dto;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter // 선언된 모든 필드의 get 메소드 생성
@RequiredArgsConstructor // 선언된 모든 final 필드가 포함된 생성자 생성 (final 이 없는 필드는 생성자에 포함되지 않는다)
public class HelloResponseDto {
    private final String name;
    private final int amount;
}

 

HelloController.java

package org.example.web;

import org.example.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 // 컨트롤러를 json으로 반환하는 컨트롤러 생성
public class HelloController {

    @GetMapping("/hello")  // http method get 요청 받는 api
    public String hello() {
        return "hello";
    }

    @GetMapping("/hello/dto")  // http method get 요청 받는 api
    public HelloResponseDto helloDto(
            @RequestParam("name") String name // 외부에서 API 로 넘긴 파라미터
            , @RequestParam("amount") int amount
    ) {
        return new HelloResponseDto(name, amount);
    }
}

 

HelloControllerTest.java

package org.example.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 org.springframework.test.web.servlet.ResultMatcher;

import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.jsonPath;
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) // 테스트 실행할 때 junit에 내장된 실행자 외에 다른 실행자 실행 : 스프링 부트 테스트와 junit 사이 연결자 역할
@WebMvcTest(controllers = HelloController.class) // 선언할 경우 @Controller, @ControllerAdvice 사용 가능, @Service, @Component, @Repository는 사용 불가능
public class HelloControllerTest {

    @Autowired
    private MockMvc mvc; // 웹 API 테스트 시 사용 (스프링 MVC 테스트의 시작점)

    @Test
    public void hello가_리턴된다() throws Exception {
        String hello = "hello";

        mvc.perform(get("/hello")) // MockMvc 통해 /hello 주소로 GET 요청
                .andExpect(status().isOk())  // mvc.perform 결과 검증 : Http Status 상태 검증
                .andExpect(content().string(hello)); // mvc.perform 결과 검증 :응답 본문 내용 검증
    }

    @Test
    public void helloDto가_리턴된다() throws Exception {
        String name = "test";
        int amount = 1000;

        mvc.perform(
                    get("/hello/dto")
                            .param("name", name) // api 테스트할 때 사용될 요청 파라미터 (단 값은 String만 허용)
                            .param("amount", String.valueOf(amount))
                ) // MockMvc 통해 /hello/dto 주소로 GET 요청
                .andExpect(status().isOk())  // mvc.perform 결과 검증 : Http Status 상태 검증
                .andExpect((ResultMatcher) jsonPath("$.name", is(name))) // json 응답값을 필드별로 검증할 수 잇는 메소드
                .andExpect((ResultMatcher) jsonPath("$.amount", is(amount)));
    }
}

 

 

스터디 환경으로 맞춘 build.gradle.kts

plugins {
    id("java")
    id("org.springframework.boot") version "2.7.13"
    id("io.spring.dependency-management") version "1.1.0"

    kotlin("plugin.spring") version "1.8.10"
    kotlin("jvm") version "1.8.10" // 사용 중인 Kotlin 버전에 맞게 조정
}

group = "org.example"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    compileOnly("org.projectlombok:lombok:1.18.26")
    annotationProcessor("org.projectlombok:lombok:1.18.26")

    implementation("org.springframework.boot:spring-boot-starter-web")

    implementation("org.jetbrains.kotlin:kotlin-stdlib")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")

    testImplementation("org.springframework.boot:spring-boot-starter-test")
    testImplementation("org.hamcrest:hamcrest:2.2")
    testImplementation("junit:junit:4.13.2")
}

tasks.test {
    useJUnit() // junit4 전용으로 실행
}

kotlin {
    jvmToolchain(8)
}

 

 

 

assertj의 장점

  • junit과 비교해서 다음과 같은 장점이 있다. 
    • CoreMatchers와 달리 추가적으로 라이브러리가 필요하지 않다. 
    • 자동완성이 확실하게 지원된다. 

 

 

▶ 예제 코드 

https://github.com/jojoldu/freelec-springboot2-webservice

 

GitHub - jojoldu/freelec-springboot2-webservice

Contribute to jojoldu/freelec-springboot2-webservice development by creating an account on GitHub.

github.com

 

 

https://product.kyobobook.co.kr/detail/S000001019679

 

스프링 부트와 AWS로 혼자 구현하는 웹 서비스 | 이동욱 - 교보문고

스프링 부트와 AWS로 혼자 구현하는 웹 서비스 | 가장 빠르고 쉽게 웹 서비스의 모든 과정을 경험한다. 경험이 실력이 되는 순간!이 책은 제목 그대로 스프링 부트와 AWS로 웹 서비스를 구현합니다

product.kyobobook.co.kr

 

반응형