TDD(Test Driven Development, 테스트 주도 개발)
소프트웨어 개발 방법론 중 하나로, 실제 코드 작성에 앞서 테스트 코드를 먼저 작성하고, 그 테스트를 통과하는 코드를 구현하는 개발 방식을 의미
단위테스트
작성한 코드가 기대하는 대로 동작을 하는지 검증 하는 절차
Jnit
Java기반의 단위 테스트를 위한 프레임워크
Annotation 기반으로 테스트를 지원하며, Assert를 통하여 검증
dependencies {
testImplementation platform('org.junit:junit-bom:5.10.0')
testImplementation 'org.junit.jupiter:junit-jupiter'
// mock 관련 의존성 추가
testImplementation("org.mockito:mockito-core:4.11.0")
testImplementation("org.mockito:mockito-junit-jupiter:4.11.0")
}
@ExtendWith(MockitoExtension.class)
public class DollarCalculatorTest {
@Mock
public MarketApi marketApi;
@BeforeEach
public void init(){
// marketApi.connect()의 결과로 3000 반환
Mockito.lenient().when(marketApi.connect()).thenReturn(3000);
}
@Test
public void testHello() {
System.out.println("hello");
}
@Test
public void dollarTest() {
MarketApi marketApi = new MarketApi();
DollarCalculator dollarCalculator = new DollarCalculator(marketApi);
dollarCalculator.init();;
Calculator calculator = new Calculator(dollarCalculator);
Assertions.assertEquals(22000,calculator.sum(10,10));
Assertions.assertEquals(0,calculator.minus(10,10));
}
@Test
public void mockTest() {
DollarCalculator dollarCalculator = new DollarCalculator(marketApi);
dollarCalculator.init();;
Calculator calculator = new Calculator(dollarCalculator);
Assertions.assertEquals(60000,calculator.sum(10,10));
Assertions.assertEquals(0,calculator.minus(10,10));
}
}
| 어노테이션 | 설명 |
| @ExtendWith(MockitoExtension.class) | JUnit 5에서 Mockito 프레임워크의 기능을 테스트 클래스에 통합해주는 확장 어노테이션. Mock 객체 자동 초기화 등 Mockito의 기능을 손쉽게 사용할 수 있게 해준다 |
| @Mock | Mockito에서 제공하는 어노테이션으로, 인터페이스나 클래스의 Mock(가짜) 객체를 생성한다. 실제 구현체 대신 가상의 객체를 만들어 테스트 대상 클래스의 격리를 가능하게 한다 |
| @BeforeEach | JUnit 5에서 각 테스트 메서드 실행 전에 공통 초기화 작업을 수행하기 위해 사용된다. 예를 들어 Mock 객체 초기화, 테스트 데이터 준비 등에 활용된다 |
| @Test | JUnit 5에서 해당 메서드가 테스트 메서드임을 나타내는 어노테이션. 이 어노테이션이 붙은 메서드는 JUnit이 자동으로 실행하여 코드의 특정 동작이 기대한 대로 동작하는지 검증한다 |
package com.example.springcalculator.component;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
@SpringBootTest
class DollarCalculatorTest {
@MockitoBean
private MarketApi marketApi;
@Autowired
private DollarCalculator dollarCalculator;
@Test
public void dollarCalculatorTest() {
Mockito.when(marketApi.connect()).thenReturn(3000);
dollarCalculator.init();
int sum = dollarCalculator.sum(10,10);
int minus = dollarCalculator.minus(10,10);
Assertions.assertEquals(60000, sum);
Assertions.assertEquals(0, minus);
}
}
@SpringBootTest
Spring Boot 애플리케이션의 전체 컨텍스트(모든 Bean)를 로드하여 실제 운영 환경과 유사하게 테스트를 진행
@MockitoBean
MarketApi 빈을 Mockito mock 객체로 대체
package com.example.springcalculator.controller;
import com.example.springcalculator.component.Calculator;
import com.example.springcalculator.component.DollarCalculator;
import com.example.springcalculator.component.MarketApi;
import com.example.springcalculator.dto.Req;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
@WebMvcTest(CalculatorApiController.class)
@Import({Calculator.class, DollarCalculator.class})
public class CalculatorApiControllerTest {
@MockitoBean
private MarketApi marketApi;
@Autowired
private MockMvc mockMvc;
@BeforeEach
public void init(){
Mockito.when(marketApi.connect()).thenReturn(3000);
}
@Test
public void sumTest() throws Exception {
// <http://localhost:8080/api/sum?a=10&b=10>
mockMvc.perform(MockMvcRequestBuilders.get("<http://localhost:8080/api/sum>")
.queryParam("a","10")
.queryParam("b","10"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string("60000"))
.andDo(MockMvcResultHandlers.print());
}
@Test
public void minusTest() throws Exception {
// <http://localhost:8080/api/minus?a=10&b=10>
Req req = new Req();
req.setA(10);
req.setB(10);
String json = new ObjectMapper().writeValueAsString(req);
// {"result":0,"response":{"resultCode":"OK"}}
mockMvc.perform(MockMvcRequestBuilders.post("<http://localhost:8080/api/minus>")
.contentType(MediaType.APPLICATION_JSON)
.content(json))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$.result").value(0))
.andExpect(MockMvcResultMatchers.jsonPath("$.response.resultCode").value("OK"))
.andDo(MockMvcResultHandlers.print());
}
}
| 어노테이션 | 주요 목적/용도 | 로드되는 빈 범위 | MockMvc 자동 등록 |
테스트 속도/무게감 | 주 사용 사례 | 장단점 요약 |
| @WebMvcTest | 컨트롤러(Web Layer) 단위 테스트 | Controller, Web 관련 빈만 |
O | 빠름/가벼움 | 컨트롤러 단위 테스트 | 장점: 빠르고 가볍다. Web Layer 집중. 단점: Service/Repository 등은 Mock 필요, 실제 환경과 다를 수 있음. |
| @SpringBootTest | 전체 애플리케이션 통합 테스트 | 모든 스프링 빈 | X (직접 추가 필요) | 느림/무거움 | 통합 테스트, 실제 환경 검증 | 장점: 실제 환경과 유사, 모든 빈 사용 가능.단점: 느리고 무거움, 디버깅 어려움. |
| @SpringBootTest @AutoConfigureMockMvc |
전체 애플리케이션 + MockMvc 테스트 | 모든 스프링 빈 | O | 느림/무거움 | 통합 테스트 + MockMvc 사용 | 장점: 실제 환경과 유사, MockMvc로 HTTP 테스트 가능. 단점: 느리고 무거움. |
'Spring' 카테고리의 다른 글
| JPA (1) | 2025.06.06 |
|---|---|
| Jacoco - 테스트 커버리지 확인하기 (1) | 2025.04.21 |
| Server to Server - RestTemplate (1) | 2025.04.16 |
| 비동기 처리하기 (1) | 2025.04.15 |
| Interceptor (0) | 2025.04.15 |