반응형
테스트 코드 소개
- 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
반응형
'스터디 > [스프링 부트와 AWS로 혼자 구현하는 웹 서비스] (2025.03)' 카테고리의 다른 글
[스프링 부트와 AWS로 혼자 구현하는 웹 서비스] 1장. 인텔리제이 스프링 부트로 시작하기 (0) | 2025.03.27 |
---|