본격적인 학습에 앞서 테스트 코드 작성법을 먼저 만나게 되었다.
자랑할 내용이 아니지만 나는 오늘 테스트 코드를 처음으로 작성해 보았다.
굳이 변명을 하자면 기능 구현이 급했던 나머지 테스트 할 시간이 없었다고 할 수 있겠다.
개인적으로 스프링부트3 묘공단이 끝나면 터커님 책으로 Go 스터디도 진행할 거다.
그를 위해 사전 작업을 하고 있는데... 그 중 하나가 유튜브에 있는 영상 다 보기다.
터커님 동영상을 보면 TDD로 코드를 작성하는 부분을 종종 볼 수 있다.
TDD가 좋다는 말은 자주 들었지만 늘 혼자 프로젝트 진행을 해 왔던 나로서는 노베에서 갑자기 TDD를 하는 일에 대한 심적 부담이 매우 컸다.
그래서 실행할 엄두를 못 내고 있었는데 터커님이 TDD하고 있는 모습을 보면 '꼭 한 번 TDD로 프로젝트를 해 봐야겠다'는 생각이 커질 정도로 결과가 좋다.
그러던 차에 스프링부트3 책에서 테스트를 먼저 경험할 수 있어 정말 정말 좋았다는 게 내가 하고 싶었던 말이다.
도입부는 여기까지 하고
'스프링부트3에서의 테스트'를 알아보자!
책에서는
유닛 테스트를 위한 JUnit(단위 테스트 프레임워크),
좀 더 나은 가독성을 위한 AssertJ(JUnit과 함께 사용할 수 있는 라이브러리),
애플리케이션을 서버에 배포하지 않고도 테스트할 수 있게
MVC 환경을 제공하는 유틸리티 클래스인 MockMvc를 맛 볼 수 있다.
여기서는 해당 툴을 약간 더 깊게 살펴 보겠다.
JUnit은 Java 프로그래밍 언어용 단위 테스팅 프레임워크다.
단위 테스트는 소프트웨어의 작은 부분(주로 개별 메소드나 함수)이 예상대로 작동하는지 검증하는 것을 목적으로 한다.
JUnit은 이러한 테스트를 쉽게 작성하고 실행할 수 있도록 지원한다.
JUnit은 다음과 같은 기능을 제공한다:
- Annotations: @Test, @Before, @After, @BeforeEach, @AfterEach 등과 같은 어노테이션을 사용하여 테스트 메서드를 정의하고, 테스트 실행 전 후의 작업을 설정할 수 있다.
- Assertions: assertEquals, assertTrue, assertFalse 등의 assertion 메서드를 제공하여 테스트 케이스의 결과를 검증한다.
- Test Runners: 테스트 케이스나 테스트 스위트를 실행할 수 있는 러너를 제공한다.
- Test Suites: 여러 테스트 클래스를 그룹화하여 한 번에 실행할 수 있다.
- Fixtures: 각 테스트가 독립적으로 실행될 수 있도록 초기 상태를 설정하거나 리소스를 정리한다.
- Matchers: assertThat 메서드와 함께 사용되며, 더 복잡한 검증을 수행할 수 있다.
- Extensibility: JUnit은 확장성이 높아서 사용자 정의 러너나 매처를 만들 수 있다.
2023년 9월 18일 기준...
JUnit 5가 최신 버전이며, JUnit 4와 비교했을 때 여러 모듈로 구성되어 있어 확장성과 유연성이 더욱 개선되었다.
JUnit 5는 JUnit Platform, JUnit Jupiter, JUnit Vintage 등 여러 서브 프로젝트로 구성되어 있다.
- JUnit Platform: 테스트를 실행하는 런처 역할을 한다.
- JUnit Jupiter: JUnit 5를 위한 새로운 프로그래밍 모델과 확장 모델을 제공한다.
- JUnit Vintage: JUnit 4와 JUnit 3의 테스트를 JUnit 5 환경에서 실행할 수 있게 한다.
JUnit은 Java 생태계에서 널리 사용되며, 다른 언어와 프레임워크에서도 영향을 미쳤다.
'그냥 영향만 미친 거다'.
엄연히 JUnit은 Java를 위한 테스팅 프레임워크다.
Java 언어에 특화되어 있다.
JUnit의 인기와 설계 철학이 다른 언어와 테스팅 프레임워크에도 영향을 미쳤을 뿐이다.
Python의 unittest, C#'s NUnit, JavaScript의 Jest 등이 JUnit의 테스팅 패러다임을 차용하거나 영향을 받았다.
JUnit 자체는 Java 외의 언어나 프레임워크에서 직접 사용할 수 없지만, 비슷한 목적의 테스팅 프레임워크가 다른 언어에서도 존재하며, 이러한 프레임워크들은 종종 JUnit과 유사한 기능과 문법을 제공한다.
만약 Java 프로젝트에서 다른 언어로 작성된 코드를 테스트하려면, 그에 맞는 테스팅 프레임워크를 사용해야 하며, JUnit은 그에 직접 적용되지는 않는다.
이런 경우에는 종종 다양한 언어의 테스팅 결과를 하나로 합치는 툴을 사용하기도 한다.
AssertJ는 Java 프로그래밍 언어용 테스트 라이브러리다.
JUnit과 같은 테스트 프레임워크와 함께 사용되며, 테스트 케이스의 검증 (assertion) 단계에서 보다 풍부하고 읽기 쉬운 API를 제공한다.
AssertJ는 테스트의 가독성을 높여주고 디버깅을 쉽게 해주는 몇 가지 유용한 기능을 제공한다.
프레임워크에서 라이브러리를 쓰는 형태구나!
주요 특징
- Fluent API: AssertJ는 메서드 체이닝을 이용한 Fluent Interface를 제공한다. 이로 인해 테스트 코드가 자연어에 가까운 형태로 작성될 수 있다.
assertThat(frodo.getName()).isEqualTo("Frodo");
- 자세한 에러 메시지: 실패한 테스트 케이스에서는 자세한 에러 메시지를 출력하여 문제를 빠르게 파악할 수 있다.
- 다양한 타입 지원: AssertJ는 자바의 다양한 타입과 클래스에 대한 특별한 assertion 메서드를 제공한다. 예를 들어, List, Map, Optional 등의 자바 표준 라이브러리 뿐만 아니라 사용자 정의 객체에 대해서도 특별한 assertion을 제공할 수 있다.
- 유연성: 사용자 정의 assertion을 쉽게 추가할 수 있다. 이를 통해 도메인 특화적인 검증 로직을 구현할 수 있다.
- Soft Assertions: 여러 개의 검증을 수행한 뒤에 한꺼번에 결과를 확인할 수 있다. 이를 통해 테스트가 중간에 실패하더라도 나머지 검증을 계속 수행할 수 있어 문제를 빠르게 파악할 수 있다.
사용 예시
import static org.assertj.core.api.Assertions.*;
public class SomeTest {
@Test
public void someTestMethod() {
List<String> names = Arrays.asList("Frodo", "Sam", "Gandalf");
assertThat(names)
.hasSize(3)
.contains("Frodo", "Sam")
.doesNotContain("Sauron");
}
}
그럴 리가 없겠지만... 나는 그렇다고 다양한 대체 프레임워크와 라이브러리를 들어본 적도 없다.
제일 많이 들어본 게 Mockito 정도.
테스팅 프레임워크나 라이브러리 중 유명한 것들은 다음과 같다.
- TestNG: TestNG는 Java용 테스팅 프레임워크로 JUnit과 유사한 기능을 제공한다. 스프링 부트는 TestNG와도 잘 통합된다.
- Mockito: Mockito는 객체 목(mock)을 생성하여 단위 테스트를 더 쉽게 작성할 수 있도록 도와주는 라이브러리입니다.
- Hamcrest: Hamcrest는 'matcher' 객체를 사용하여 테스트 검증을 보다 선언적으로 수행할 수 있게 도와주는 라이브러리다.
- Spock: Spock은 Groovy 기반의 테스팅 프레임워크로, BDD (Behavior-Driven Development) 스타일의 테스트를 지원한다.
- Cucumber: Cucumber는 BDD를 지원하는 또 다른 테스팅 툴이다. Gherkin이라는 도메인 특화 언어를 사용하여 테스트 케이스를 작성한다.
- WebTestClient: 스프링 5와 함께 제공되는 WebTestClient는 리액티브 웹 애플리케이션을 테스트하기 위한 라이브러리다.
- Spring Test: 스프링 자체에 내장된 spring-test 모듈은 MockMvc와 같은 유용한 테스팅 유틸리티를 제공한다.
- Selenium: 웹 애플리케이션의 UI 테스트를 자동화하기 위한 도구다.
- RestAssured: RESTful API를 테스트하기 위한 Java 라이브러리다.
- JUnit 5 Extensions: 스프링부트는 JUnit 5의 다양한 확장 기능을 지원한다. 예를 들어 @ExtendWith를 사용하여 스프링의 ApplicationContext를 테스트에 쉽게 통합할 수 있다.
MockMvc는 스프링 프레임워크에서 제공하는 웹 애플리케이션 테스트를 위한 유틸리티다.
이를 사용하면, 실제로 웹 서버를 실행하지 않고도 스프링 MVC의 DispatcherServlet을 통해 HTTP 요청 및 응답을 모의(mock) 테스트할 수 있다.
이 방식은 웹 계층의 통합 테스트와 단위 테스트에 유용하며, 테스트 실행 속도가 빠르다는 장점이 있다.
MockMvc를 사용하면 컨트롤러의 로직을 정확하게 테스트할 수 있고, 예상되는 요청과 응답에 대해 세세하게 검증할 수 있다.
예를 들어, 특정 URL로 GET 또는 POST 요청을 보내고, 결과로 받는 HTTP 상태 코드, 헤더, 응답 본문 등을 체크할 수 있다.
기본 사용 예시
import org.junit.jupiter.api.Test;
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.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
public class MyControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void shouldReturnDefaultMessage() throws Exception {
mockMvc.perform(get("/"))
.andExpect(status().isOk());
}
}
이렇게 테스트하면 루트 URL('/')에 HTTP GET 요청을 했을 때, 이가 성공적으로 처리되어 HTTP 상태 코드 200(OK)을 반환하는지 확인할 수 있다.
주요 기능
- Request Building: MockMvcRequestBuilders를 사용하여 다양한 HTTP 메소드(GET, POST, PUT, DELETE 등)와 파라미터, 헤더 등을 설정할 수 있다.
- Result Matching: MockMvcResultMatchers를 사용하여 응답의 상태 코드, 헤더, 본문 등을 검증할 수 있다.
- Exception Handling: 컨트롤러에서 발생한 예외를 캐치하고 검증할 수 있다.
- Content Type: JSON, XML 등 다양한 컨텐트 타입을 지원하며, jsonPath나 xpath를 사용해 본문을 세세하게 검증할 수 있다.
MockMvc는 테스트 환경에서만 사용되며 실제 프로덕션 코드에는 포함되지 않습니다. 이는 Spring MVC 애플리케이션의 테스트를 보다 간단하고 정확하게 수행할 수 있도록 도와줍니다.
5장까지 학습하고
💖마딛는 로제 떡볶이💖를 먹어야겠다!
이 글은 골든래빗 《스프링 부트 3 백엔드 개발자 되기 - 자바 편》의 4장 써머리입니다.