스프링 부트 공식 레퍼런스를 한글로 번역한 문서입니다.
전체 목차는 여기에 있습니다.
목차
- 7.26.1. Test Scope Dependencies
- 7.26.2. Testing Spring Applications
- 7.26.3. Testing Spring Boot Applications
- Detecting Web Application Type
- Detecting Test Configuration
- Excluding Test Configuration
- Using Application Arguments
- Testing with a mock environment
- Testing with a running server
- Customizing WebTestClient
- Using JMX
- Using Metrics
- Mocking and Spying Beans
- Auto-configured Tests
- Auto-configured JSON Tests
- Auto-configured Spring MVC Tests
- Auto-configured Spring WebFlux Tests
- Auto-configured Data Cassandra Tests
- Auto-configured Data JPA Tests
- Auto-configured JDBC Tests
- Auto-configured Data JDBC Tests
- Auto-configured jOOQ Tests
- Auto-configured Data MongoDB Tests
- Auto-configured Data Neo4j Tests
- Auto-configured Data Redis Tests
- Auto-configured Data LDAP Tests
- Auto-configured REST Clients
- Auto-configured Spring REST Docs Tests
- Auto-configured Spring Web Services Tests
- Additional Auto-configuration and Slicing
- User Configuration and Slicing
- Using Spock to Test Spring Boot Applications
- 7.26.4. Test Utilities
7.26. Testing
스프링 부트는 애플리케이션 테스트를 도와줄 다양한 유틸리티와 어노테이션을 제공한다. 핵심 아이템들을 가지고 있는 spring-boot-test
와, 테스트를 위한 자동 설정을 지원하는 spring-boot-test-autoconfigure
, 이 두 가지 모듈로 테스트를 지원한다.
대부분의 개발자들은 스프링 부트 테스트 모듈과 함께 JUnit Jupiter, AssertJ, Hamcrest 등의 여러 가지 유용한 라이브러리를 함께 가져오는 spring-boot-starter-test
“스타터”를 사용한다.
JUnit 4를 사용하는 테스트가 있을 때는 JUnit 5의 vintage 엔진으로 실행할 수 있다. vintage 엔진을 사용하려면 아래처럼
junit-vintage-engine
의존성을 추가해라.<dependency> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-core</artifactId> </exclusion> </exclusions> </dependency>
spring-boot-starter-test
에 들어있는 org.hamcrest:hamcrest
를 사용하기 위해 hamcrest-core
는 제외한다.
7.26.1. Test Scope Dependencies
spring-boot-starter-test
“스타터”는 다음과 같은 라이브러리를 포함하고 있다 (test
scope
):
- JUnit 5: 자바 애플리케이션의 단위 테스트를 위한 실질적인 표준.
- Spring Test & Spring Boot Test: 스프링 부트 애플리케이션을 위한 테스트 유틸리티와 테스트 통합 지원.
- AssertJ: fluent assertion 라이브러리.
- Hamcrest: matcher 객체 (constraint, predicate로도 알려진) 라이브러리.
- Mockito: 자바 모킹 프레임워크.
- JSONassert: JSON을 위한 assertion 라이브러리.
- JsonPath: JSON 전용 XPath.
테스트를 작성할 때 일반적으로 많이 쓰는 라이브러리들을 모아놨다. 이런 라이브러리가 요구사항에 잘 맞지 않으면, 자체 테스트 의존성을 별도로 추가해도 된다.
7.26.2. Testing Spring Applications
의존성 주입의 큰 장점 중 하나는 코드를 단위 테스트하기가 쉬워진다는 거다. 심지어 스프링을 사용하지 않고도 new
연산자로 객체 인스턴스를 만들 수 있다. 실제 의존성 대신 mock 객체를 사용할 수도 있다.
단위 테스트를 넘어 통합 테스트를 시작해야 할 때가 자주 있다 (스프링 ApplicationContext
를 사용해서). 애플리케이션을 배포하거나 다른 인프라에 연결하지 않고도 통합 테스트를 수행할 수 있으면 매우 유용할 거다.
스프링 프레임워크에는 이런 통합 테스트를 위한 전용 테스트 모듈이 따로 있다. org.springframework:spring-test
의존성을 직접 선언해도 되고, spring-boot-starter-test
“스타터”를 통해 간접적으로transitively 의존성을 가져와도 된다.
전에 spring-test
모듈을 사용해본 적이 없다면 먼저 스프링 프레임워크 레퍼런스 문서에서 관련 섹션을 읽어보고 오는 게 좋다.
7.26.3. Testing Spring Boot Applications
스프링 부트 애플리케이션도 결국 스프링 ApplicationContext
기 때문에, 테스트를 위해 평소 순수vanilla 스프링 컨텍스트로 설정해주는 것 외엔 특별히 해야 할 일은 없다.
외부 프로퍼티, 로깅 등, 스프링 부트의 기능들은
SpringApplication
을 통해 컨텍스트를 생성할 때만 기본으로 컨텍스트에 설치된다.
스프링 부트는 스프링 부트 기능이 필요할 때 표준 spring-test
@ContextConfiguration
어노테이션 대신 사용할 수 있는 @SpringBootTest
어노테이션을 제공한다. 이 어노테이션은 SpringApplication
을 통해 테스트에 사용할 ApplicationContext
를 생성하는 식으로 동작한다. @SpringBootTest
외에도, 좀 더 구체적인 애플리케이션의 슬라이스를 테스트할 수 있는 여러 가지 어노테이션들도 제공한다.
JUnit 4를 사용한다면 테스트에
@RunWith(SpringRunner.class)
를 추가하는 것을 잊지 마라. 추가해주지 않으면 이 어노테이션들을 무시한다. JUnit 5를 사용할 때는 이와 동일한@ExtendWith(SpringExtension.class)
를 추가해주지 않아도 되는데,@SpringBootTest
나 다른@…Test
어노테이션에 이미 선언돼 있기 때문이다.
기본적으로 @SpringBootTest
는 서버를 시작하지 않는다. @SpringBootTest
의 webEnvironment
속성을 사용하면 테스트 실행 방법을 더욱 세분화할 수 있다:
MOCK
(디폴트): 웹ApplicationContext
를 로드하고 mock 웹 환경을 제공한다. 이 어노테이션을 사용할 땐 임베디드 서버를 시작하지 않는다. 이 모드는 클래스패스에 웹 환경이 없으면 자동으로 웹이 아닌 일반ApplicationContext
를 만드는 것으로 폴백한다.@AutoConfigureMockMvc
나@AutoConfigureWebTestClient
와 함께 사용해서 mock 기반으로 웹 애플리케이션을 테스트할 수 있다.RANDOM_PORT
:WebServerApplicationContext
를 로드하고 실제 웹 환경을 제공한다. 임베디드 서버를 띄워 랜덤 포트에서 수신listen을 시작한다.DEFINED_PORT
:WebServerApplicationContext
를 로드하고 실제 웹 환경을 제공한다. 임베디드 서버를 띄워 (application.properties
에) 정의한 포트나 디폴트 포트8080
에서 수신listen을 시작한다.NONE
:SpringApplication
을 사용해서ApplicationContext
를 로드하지만, 웹 환경(mock 등)은 아무것도 제공하지 않는다.
테스트가
@Transactional
일 때는 기본적으로 각 테스트 메소드가 끝나면 트랜잭션을 롤백한다. 하지만RANDOM_PORT
나DEFINED_PORT
와 함께 쓰면 실제 서블릿 환경을 제공한다는 걸 암시하기 때문에, HTTP 클라이언트와 서버는 별도 스레드에서 실행되고, 따라서 별도 트랜잭션에서 실행된다. 이럴 땐 서버에서 시작한 트랜잭션은 롤백되지 않는다.
애플리케이션이 management 서버에 다른 포트를 사용할 때는,
@SpringBootTest
에서webEnvironment = WebEnvironment.RANDOM_PORT
를 사용하면 management 서버도 별도의 랜덤 포트에서 시작한다.
Detecting Web Application Type
클래스패스에 스프링 MVC가 있으면 전형적인 MVC 기반 애플리케이션 컨텍스트를 설정한다. 스프링 웹플럭스만 있을 땐 이를 감지해서, 그대신 웹플럭스 기반 애플리케이션 컨텍스트를 설정한다.
둘 다 있을 때는 스프링 MVC를 우선시한다. 이럴 때 리액티브 웹 애플리케이션을 테스트하고 싶으면, 반드시 spring.main.web-application-type
프로퍼티를 설정해야 한다:
@SpringBootTest(properties = "spring.main.web-application-type=reactive")
class MyWebFluxTests {
// ...
}
Detecting Test Configuration
스프링 테스트 프레임워크를 많이 사용해봤다면, @ContextConfiguration(classes=…)
를 사용해 로드할 스프링 @Configuration
을 지정하는 것에 익숙할 거다. 아니면 테스트 코드 안에 @Configuration
클래스를 중첩해서 자주 사용했을 거다.
스프링 부트 애플리케이션을 테스트할 때는 보통은 그럴 필요가 없다. 설정을 명시해주지 않았을 땐 언제나 스프링 부트의 @*Test
어노테이션이 주요 설정을 자동으로 검색한다.
이 검색 알고리즘에선 @SpringBootApplication
이나 @SpringBootConfiguration
어노테이션이 달린 클래스를 찾을 때까지 테스트가 포함된 패키지를 탐색한다. 베스트 프랙티스에 맞게 코드 구조를 잡으면 보통은 메인 설정을 찾는다.
테스트 어노테이션으로 좀 더 세세한 애플리케이션의 슬라이스를 테스트한다면, 메인 메소드를 가진 애플리케이션 클래스엔 특정 영역에 귀속된 설정을 추가하지 않는 것이 좋다.
@SpringBootApplication
에서는 사용하는 컴포넌트 스캔 설정에 예외 필터를 정의하며, 이 필터를 사용해서 슬라이싱이 예상대로 동작하는지 확인한다.@SpringBootApplication
어노테이션을 선언한 클래스에@ComponentScan
명령을 명시하게되면, 이 필터를 비활성화한다는 점을 유의해라. 슬라이싱을 사용하려면 필터를 다시 정의해야 한다.
주요 설정을 커스텀하고 싶으면 @TestConfiguration
클래스를 중첩해서 사용하면 된다. @Configuration
클래스를 중첩하면 애플리케이션의 주요 설정 대신 사용하지만, 이와는 달리 @TestConfiguration
클래스를 중첩하면 애플리케이션의 주요 설정 위에 추가된다.
스프링의 테스트 프레임워크는 애플리케이션 컨텍스트를 캐시해서 여러 테스트에 사용한다. 따라서 여러 테스트에서 같은 설정을 공유하기만 하면 (설정을 검색하는 방법과는 상관없이), 많은 시간이 소요되곤 하는 컨텍스트 로드 프로세스는 딱 한 번만 일어난다.
Excluding Test Configuration
컴포넌트 스캔을 이용하고 있다면 (ex. @SpringBootApplication
이나 @ComponentScan
을 사용한다면), 특정 테스트용으로만 생성한 최상위 설정 클래스를 의도치않게 모든 곳에서 사용하고 있는 것을 발견할 수도 있다.
앞에서도 살펴봤지만 주요 설정을 커스텀할 때는 @TestConfiguration
을 테스트의 내부 클래스에 사용할 수 있다. 이 @TestConfiguration
을 최상위 클래스에 두게 되면, 스캔 중에 @TestConfiguration
클래스들은 src/test/java
에 있더라도 선택하지 않아야 된다는 걸 나타낸다. @TestConfiguration
을 선언한 클래스를 사용하려면 다음 예제처럼 필요한 위치에 직접 임포트하면 된다:
@SpringBootTest
@Import(MyTestsConfiguration.class)
class MyTests {
@Test
void exampleTest() {
// ...
}
}
@ComponentScan
을 직접 사용할 때는 (다시 말해@SpringBootApplication
을 통하지 않으면),TypeExcludeFilter
도 함께 등록해야 한다. 자세한 내용은 Javadoc을 참고해라.
Using Application Arguments
애플리케이션에서 인자를 받고 있다면, @SpringBootTest
의 args
속성을 사용해서 인자를 주입시킬 수 있다:
@SpringBootTest(args = "--app.test=one")
class MyApplicationArgumentTests {
@Test
void applicationArgumentsPopulated(@Autowired ApplicationArguments args) {
assertThat(args.getOptionNames()).containsOnly("app.test");
assertThat(args.getOptionValues("app.test")).containsOnly("one");
}
}
Testing with a mock environment
기본적으로 @SpringBootTest
는 서버를 시작하지 않는다. 이 mock 환경으로 테스트해보고 싶은 웹 엔드포인트가 있을 땐 아래 예제처럼 MockMvc
를 별도로 추가하면 된다:
@SpringBootTest
@AutoConfigureMockMvc
class MyMockMvcTests {
@Test
void exampleTest(@Autowired MockMvc mvc) throws Exception {
mvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("Hello World"));
}
}
모든 걸 다 갖춘
ApplicationContext
를 시작하기 보단 웹 레이어에만 집중하고 싶으면 이대신@WebMvcTest
사용을 검토해봐라.
아니면 다음 예제처럼 WebTestClient
를 설정해도 된다:
@SpringBootTest
@AutoConfigureWebTestClient
class MyMockWebTestClientTests {
@Test
void exampleTest(@Autowired WebTestClient webClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello World");
}
}
모킹한 환경을 통해 테스트를 수행하면 보통 서블릿 컨테이너를 통째로 실행할 때보다 빠르다. 하지만 모킹은 스프링 MVC 계층에서 이뤄지기 때문에, 저수준에 있는 서블릿 컨테이너 동작에 의존하는 코드는 MockMvc로는 바로 테스트할 수 없다.
예를 들어, 스프링 부트는 서블릿 컨테이너에서 제공하는 “에러 페이지”를 기반으로 에러를 처리한다. 즉, MVC 계층에서 예상대로 예외를 던지고 처리하는지는 테스트할 수 있지만, 특정 커스텀 에러 페이지가 렌더링되는지는 직접 테스트할 수 없다는 뜻이다. 이렇게 저수준에 있는 관심사를 테스트해야 할 때는 다음 섹션에 설명하는 방법대로 서버 전체를 실행시키면 된다.
Testing with a running server
전체를 다 실행하는 서버를 시작해야 할 때는 랜덤 포트를 사용하는 게 좋다. @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
를 사용하면 테스트를 실행할 때마다 사용 가능한 포트를 무작위로 고른다.
@LocalServerPort
어노테이션을 사용하면 테스트에 실제로 사용한 포트를 주입할 수 있다. 기동시킨 서버에 REST 호출을 날려야 하는 테스트에선 편의상 아래 예제처럼 WebTestClient
를 추가로 @Autowire
해도 된다. WebTestClient
는 실행 중인 서버에 대한 상대적인 링크를 리졸브하며, 응답 검증을 위한 전용 API를 함께 제공한다:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyRandomPortWebTestClientTests {
@Test
void exampleTest(@Autowired WebTestClient webClient) {
webClient
.get().uri("/")
.exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello World");
}
}
이 구조에서는 클래스패스에 spring-webflux
가 있어야 한다. 웹플럭스를 추가할 수 없거나, 추가할 생각이 없다면, 스프링 부트는 TestRestTemplate
도 제공하고 있다:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyRandomPortTestRestTemplateTests {
@Test
void exampleTest(@Autowired TestRestTemplate restTemplate) {
String body = restTemplate.getForObject("/", String.class);
assertThat(body).isEqualTo("Hello World");
}
}
Customizing WebTestClient
WebTestClient
빈을 커스텀하고 싶으면 WebTestClientBuilderCustomizer
빈을 설정해라. Customizer 빈들은 WebTestClient
를 생성할 때 사용하는 WebTestClient.Builder
를 넘겨서 호출한다.
Using JMX
테스트 컨텍스트 프레임워크는 컨텍스트를 캐시하기 때문에, JMX는 동일한 컴포넌트들을 같은 도메인에 등록하지 않도록 기본적으로 비활성화한다. 이런 테스트에서 MBeanServer
에 접근해야 한다면 dirty로 마킹하는 것도 고려해봐라:
@ExtendWith(SpringExtension.class)
@SpringBootTest(properties = "spring.jmx.enabled=true")
@DirtiesContext
class MyJmxTests {
@Autowired
private MBeanServer mBeanServer;
@Test
void exampleTest() throws MalformedObjectNameException {
assertThat(this.mBeanServer.getDomains()).contains("java.lang");
// ...
}
}
Using Metrics
클래스패스에 어떤 게 들어 있더라도, @SpringBootTest
를 사용할 때는 meter 레지스트리는 인메모리를 사용하는 레지스트리 외엔 자동으로 설정되지 않는다.
통합 테스트에서 메트릭을 다른 백엔드로 내보내고 싶으면 @AutoConfigureMetrics
어노테이션을 추가해라.
Mocking and Spying Beans
테스트를 실행할 때는 애플리케이션 컨텍스트 내에 있는 특정 컴포넌트를 모킹해야 하는 때가 종종 있다. 예를 들어, 개발 중에는 사용할 수 없는 어떤 리모트 서비스를 이용하는 파사드가 있을 수 있다. 실제 환경에서 트리거하긴 어려운 실패 상황을 시뮬레이션하고 싶을 때도 모킹이 유용할 거다.
스프링 부트에는 ApplicationContext
안에 있는 빈을 위한 Mockito mock을 정의할 수 있는 @MockBean
어노테이션이 들어있다. 이 어노테이션을 사용하면 빈을 새로 추가하거나, 기존에 있던 빈 정의 하나를 대체할 수 있다. 테스트 클래스에 어노테이션을 바로 사용해도 되고, 테스트 안에 있는 필드나, @Configuration
클래스 및 필드에 사용해도 된다. 필드에 사용하면 mock 인스턴스를 만들어 주입까지 해준다. Mock 빈은 각 테스트 메소드를 실행한 후에 자동으로 리셋된다.
테스트에 스프링 부트의 테스트 어노테이션 중 하나를 사용하고 있다면 (ex.
@SpringBootTest
), 이 기능은 자동으로 활성화된다. 이 기능을 다른 구조에서 사용하려면 다음 예제처럼 반드시 리스너를 명시적으로 추가해줘야 한다:@ContextConfiguration(classes = MyConfig.class) @TestExecutionListeners({ MockitoTestExecutionListener.class, ResetMocksTestExecutionListener.class }) class MyTests { // ... }
아래 예제에선 기존 RemoteService
빈을 mock 구현체로 대체하고 있다:
@SpringBootTest
class MyTests {
@Autowired
private Reverser reverser;
@MockBean
private RemoteService remoteService;
@Test
void exampleTest() {
given(this.remoteService.getValue()).willReturn("spring");
String reverse = this.reverser.getReverseValue(); // Calls injected RemoteService
assertThat(reverse).isEqualTo("gnirps");
}
}
@MockBean
으로는 애플리케이션 컨텍스트를 리프레시하는 중에 실행되는 빈 동작은 모킹할 수 없다. 테스트가 실행되는 시점에는 애플리케이션 컨텍스트 리프레시가 완료돼 있을 거고, 모킹한 동작을 설정하기에는 너무 늦는다. 이런 상황에서는@Bean
메소드를 통해 mock을 생성하고 설정하는 게 좋다.
추가로, @SpyBean
을 사용하면 기존 빈을 Mockito spy
로 래핑할 수 있다. 자세한 내용은 Javadoc을 참고해라.
범위가 한정된scoped 빈에다가 프록시를 생성하는 등, CGLib 프록시를 만들게 되면 프록시하는 메소드를
final
으로 선언한다. 이렇게 되면 디폴트 설정에선final
메소드에 mock이나 spy를 적용할 수 없기 때문에, Mockito는 더 이상 제대로 동작하지 않는다. 이런 빈에 mock이나 spy를 적용하려면 애플리케이션의 테스트 의존성에org.mockito:mockito-inline
을 추가해서 Mockito에서 inline mock maker를 사용하도록 설정해라. inline mock maker는 Mockito가final
메소드에 mock과 spy를 적용할 수 있게 해준다.
스프링의 테스트 프레임워크는 여러 테스트를 실행하면서 애플리케이션 컨텍스트를 캐시하고, 같은 설정을 공유하는 테스트에선 컨텍스트를 재사용하지만,
@MockBean
이나@SpyBean
을 사용하면 캐시 키가 달라질 수 있어서 컨텍스트 갯수가 늘어날 가능성이 크다.
@Cacheable
메소드에서 이름으로 파라미터를 참조하고 있는 빈에@SpyBean
으로 spy를 적용하는 경우, 반드시 애플리케이션을-parameters
로 컴파일해야 한다. 이렇게 해야 빈에 spy를 적용한 다음 캐시 인프라에서 파라미터 이름을 활용할 수 있다.
스프링에서 프록시로 감싸는 빈에
@SpyBean
을 통해 spy를 적용할 때는, 상황에 따라 스프링의 프록시를 제거해야 할 수도 있다. 예를 들어given
이나when
을 사용해서 기대값을 설정할 때가 그렇다. 이럴 땐AopTestUtils.getTargetObject(yourProxiedSpy)
를 사용해라.
Auto-configured Tests
스프링 부트의 자동 설정 시스템은 대부분의 애플리케이션에 잘 맞지만, 간혹 테스트에 사용하기엔 너무 과할 때도 있다. 애플리케이션의 “조각slice“을 테스트하는 데 필요한 일부 설정만 로드할 수 있으면 종종 유용할 거다. 예를 들어, 스프링 MVC 컨트롤러가 URL을 제대로 매핑하는지 테스트하고 싶은데 이 테스트에선 데이터베이스 호출은 제외시키고 싶을 수도 있고, JPA 엔티티를 테스트하고 싶지만 웹 레이어에는 관심이 없을 수도 있다.
spring-boot-test-autoconfigure
모듈에는 이런 “슬라이스”들을 자동으로 설정할 때 활용할 수 있는 여러 가지 어노테이션들이 들어있다. 이 어노테이션들은 전부 유사한 방식으로 동작하며, ApplicationContext
를 로드하는 @…Test
어노테이션과, 자동 설정을 커스텀할 수 있는 @AutoConfigure…
어노테이션을 하나 이상 제공한다.
각 슬라이스는 컴포넌트 스캔을 적당한 컴포넌트들로 제한하며, 로드하는 자동 설정 클래스도 매우 한정적이다. 그 중에서도 하나를 제외해야 한다면,
@…Test
어노테이션 대부분은excludeAutoConfiguration
속성을 제공한다. 아니면@ImportAutoConfiguration#exclude
를 사용해도 된다.
테스트 하나에서
@…Test
어노테이션을 여러 개 사용하는 식으로 “슬라이스”를 여러개 추가하는 건 지원하지 않는다. “슬라이스”가 여러 개 필요한 경우@…Test
어노테이션 중에서 하나를 고르고, 다른 “슬라이스”는@AutoConfigure…
어노테이션으로 직접 추가해라.
@AutoConfigure…
어노테이션은 표준@SpringBootTest
어노테이션과도 함께 사용할 수 있다. 애플리케이션을 “슬라이싱”하는 것에는 관심 없지만, 테스트 빈을 자동 설정하고 싶다면 이 조합을 사용하면 된다.
Auto-configured JSON Tests
객체가 예상대로 JSON으로 직렬화되고 역직렬화되는지를 테스트하려면 @JsonTest
어노테이션을 사용하면 된다. @JsonTest
는 지원하는 JSON 매퍼를 찾아 자동 설정한다. 지원하는 라이브러리는 다음과 같다:
- Jackson
ObjectMapper
, 모든@JsonComponent
빈, 모든 JacksonModule
들 Gson
Jsonb
@JsonTest
로 활성화되는 자동 설정들은 부록에서 확인할 수 있다.
자동 설정되는 헬퍼를 따로 설정하고 싶을 땐 @AutoConfigureJsonTesters
어노테이션을 사용하면 된다.
스프링 부트에는 JSONAssert와 JsonPath 라이브러리와 함께 동작하는 AssertJ 기반 헬퍼가 들어있는데, 이 헬퍼로 JSON을 기대한 대로 만들 수 있는지 검증할 수 있다. JacksonTester
, GsonTester
, JsonbTester
, BasicJsonTester
클래스는 각각 Jackson, Gson, Jsonb, Strings에 이용할 수 있다. @JsonTest
를 사용하면 모든 헬퍼를 테스트 클래스의 필드로 @Autowired
할 수 있다. 다음은 Jackson을 위한 테스트 클래스 예시다:
@JsonTest
class MyJsonTests {
@Autowired
private JacksonTester<VehicleDetails> json;
@Test
void serialize() throws Exception {
VehicleDetails details = new VehicleDetails("Honda", "Civic");
// Assert against a `.json` file in the same package as the test
assertThat(this.json.write(details)).isEqualToJson("expected.json");
// Or use JSON path based assertions
assertThat(this.json.write(details)).hasJsonPathStringValue("@.make");
assertThat(this.json.write(details)).extractingJsonPathStringValue("@.make").isEqualTo("Honda");
}
@Test
void deserialize() throws Exception {
String content = "{\"make\":\"Ford\",\"model\":\"Focus\"}";
assertThat(this.json.parse(content)).isEqualTo(new VehicleDetails("Ford", "Focus"));
assertThat(this.json.parseObject(content).getMake()).isEqualTo("Ford");
}
}
JSON 헬퍼 클래스들은 표준 단위 테스트에도 직접 사용할 수 있다.
@JsonTest
를 사용하지 않을 때는@Before
메소드에서 헬퍼의initFields
메소드를 호출해라.
스프링 부트의 AssertJ 기반 헬퍼를 통해 주어진 JSON path에서 숫자 값을 검증할 때는, 타입에 따라 isEqualTo
를 쓰지 못할 수도 있다. 이럴 땐 isEqualTo
대신 AssertJ의 satisfies
를 사용해서 값이 주어진 조건과 일치하는지 검증할 수 있다. 예를 들어 아래 예제에선 실제 숫자가 오프셋 0.01
내로 0.15
에 근접한 float 값인지를 검증한다.
@Test
void someTest() throws Exception {
SomeObject value = new SomeObject(0.152f);
assertThat(this.json.write(value)).extractingJsonPathNumberValue("@.test.numberValue")
.satisfies((number) -> assertThat(number.floatValue()).isCloseTo(0.15f, within(0.01f)));
}
Auto-configured Spring MVC Tests
스프링 MVC 컨트롤러가 예상대로 동작하는지를 테스트하려면 @WebMvcTest
어노테이션을 사용해라. @WebMvcTest
는 스프링 MVC 인프라를 자동 설정하고, 스캔하는 빈을 @Controller
, @ControllerAdvice
, @JsonComponent
, Converter
, GenericConverter
, Filter
, HandlerInterceptor
, WebMvcConfigurer
, HandlerMethodArgumentResolver
로 제한한다. @WebMvcTest
어노테이션을 사용할 땐 전형적인 @Component
와 @ConfigurationProperties
빈은 스캔하지 않는다. @ConfigurationProperties
빈을 포함시키려면 @EnableConfigurationProperties
를 사용하면 된다.
@WebMvcTest
로 활성화되는 자동 설정들은 부록에서 확인할 수 있다.
Jackson
Module
같이 다른 컴포넌트들도 등록해야 한다면, 테스트에@Import
를 사용하면 별도 설정 클래스를 임포트할 수 있다.
@WebMvcTest
는 보통 단일 컨트롤러로 제한하며, @MockBean
과 함께 사용해서 필요한 조력 컴포넌트의 mock 구현체를 제공한다.
@WebMvcTest
는 MockMvc
도 자동 설정한다. Mock MVC를 사용하면 HTTP 서버를 통째로 기동하지 않고도 MVC 컨트롤러를 빠르고 확실하게 테스트해볼 수 있다.
@WebMvcTest
가 아닐 때도 (@SpringBootTest
등)@AutoConfigureMockMvc
어노테이션을 달면MockMvc
를 자동 설정할 수 있다. 다음은MockMvc
를 사용하는 예시다:
@WebMvcTest(UserVehicleController.class)
class MyControllerTests {
@Autowired
private MockMvc mvc;
@MockBean
private UserVehicleService userVehicleService;
@Test
void testExample() throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda", "Civic"));
this.mvc.perform(get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andExpect(content().string("Honda Civic"));
}
}
자동 설정되는 요소들을 따로 설정하고 싶을 땐 (예를 들어 서블릿 필터를 적용해야 한다면)
@AutoConfigureMockMvc
어노테이션의 속성을 이용하면 된다.
HtmlUnit이나 Selenium을 사용한다면, 자동 설정은 HtmlUnit WebClient
빈이나 Selenium WebDriver
빈도 함께 제공한다. 다음 예제에선 HtmlUnit을 사용한다:
@WebMvcTest(UserVehicleController.class)
class MyHtmlUnitTests {
@Autowired
private WebClient webClient;
@MockBean
private UserVehicleService userVehicleService;
@Test
void testExample() throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot")).willReturn(new VehicleDetails("Honda", "Civic"));
HtmlPage page = this.webClient.getPage("/sboot/vehicle.html");
assertThat(page.getBody().getTextContent()).isEqualTo("Honda Civic");
}
}
기본적으로 스프링 부트는 각 테스트를 완료하고 나면 드라이버를 종료하고 새 인스턴스를 주입할 수 있도록
WebDriver
빈을 특별한 “스코프”에 넣는다. 이 동작이 싫다면WebDriver
@Bean
을 정의해서@Scope("singleton")
을 추가하면 된다.
스프링 부트에서 생성한
webDriver
스코프는 같은 이름을 가진 사용자 정의 스코프를 대체한다.@WebMvcTest
를 사용할 때 자체webDriver
스코프를 정의하면 동작이 멈출 수도 있다.
클래스패스에 스프링 시큐리티가 있다면 @WebMvcTest
는 WebSecurityConfigurer
빈도 함께 스캔한다. 이럴 때 테스트에서 완전히 보안을 비활성화하기 보단, 스프링 시큐리티의 테스트 지원을 이용할 수 있다. 어떻게 스프링 시큐리티의 MockMvc
지원을 이용할 수 있는지는 how-to 섹션 테스트에 스프링 시큐리티 활용하기에서 확인할 수 있다.
스프링 MVC 테스트를 작성하는 것만으로는 충분하지 않을 때가 있다. 스프링 부트는 실제 서버를 통한 완전한 end-to-end 테스트 실행도 도와준다.
Auto-configured Spring WebFlux Tests
스프링 웹플럭스 컨트롤러가 예상대로 동작하는지를 테스트하려면 @WebFluxTest
어노테이션을 사용해라. @WebFluxTest
는 스프링 웹플럭스 인프라를 자동 설정하고, 스캔하는 빈을 @Controller
, @ControllerAdvice
, @JsonComponent
, Converter
, GenericConverter
, WebFilter
, WebFluxConfigurer
로 제한한다. @WebFluxTest
어노테이션을 사용할 땐 전형적인 @Component
와 @ConfigurationProperties
빈은 스캔하지 않는다. @ConfigurationProperties
빈을 포함시키려면 @EnableConfigurationProperties
를 사용하면 된다.
@WebFluxTest
로 활성화되는 자동 설정들은 부록에서 확인할 수 있다.
Jackson
Module
같이 다른 컴포넌트들도 등록해야 한다면, 테스트에@Import
를 사용하면 별도 설정 클래스를 임포트할 수 있다.
@WebFluxTest
는 보통 단일 컨트롤러로 제한하며, @MockBean
과 함께 사용해서 필요한 조력 컴포넌트의 mock 구현체를 제공한다.
@WebFluxTest
는 WebTestClient
도 자동 설정한다. WebTestClient
를 사용하면 HTTP 서버를 통째로 기동하지 않고도 웹플럭스 컨트롤러를 빠르고 확실하게 테스트해볼 수 있다.
@WebFluxTest
가 아닐 때도 (@SpringBootTest
등)@AutoConfigureWebTestClient
어노테이션을 달면WebTestClient
를 자동 설정할 수 있다. 아래 예제에선@WebFluxTest
와WebTestClient
를 함께 사용하는 클래스를 보여주고 있다:
@WebFluxTest(UserVehicleController.class)
class MyControllerTests {
@Autowired
private WebTestClient webClient;
@MockBean
private UserVehicleService userVehicleService;
@Test
void testExample() throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda", "Civic"));
this.webClient.get().uri("/sboot/vehicle").accept(MediaType.TEXT_PLAIN).exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Honda Civic");
}
}
mock 웹 애플리케이션에
WebTestClient
를 사용하는 건 현재로썬 웹플럭스에서만 동작하기 때문에, 이 구조는 웹플럭스 애플리케이션에서만 지원한다.
@WebFluxTest
는 함수형 웹 프레임워크를 통해 등록한 라우트는 감지하지 못한다. 컨텍스트에 있는RouterFunction
빈을 테스트하려면@Import
를 통해 직접RouterFunction
을 임포트하거나@SpringBootTest
를 사용하는 게 좋다.
@WebFluxTest
는SecurityWebFilterChain
타입@Bean
을 통해 등록한 커스텀 시큐리티 설정은 감지하지 못한다. 테스트에서 사용하려면@Import
를 통해 빈을 등록하고 있는 설정을 임포트하거나@SpringBootTest
를 사용해야 할 거다.
스프링 웹플럭스 테스트를 작성하는 것만으로는 충분하지 않을 때가 있다. 스프링 부트는 실제 서버를 통한 완전한 end-to-end 테스트 실행도 도와준다.
Auto-configured Data Cassandra Tests
Cassandra 애플리케이션을 테스트할 땐 @DataCassandraTest
를 사용할 수 있다. 이 어노테이션은 기본적으로 CassandraTemplate
을 설정하고, @Table
클래스를 스캔하며, Spring Data Cassandra 레포지토리를 구성한다. @DataCassandraTest
어노테이션을 사용할 때는 전형적인 @Component
와 @ConfigurationProperties
빈은 스캔하지 않는다. @ConfigurationProperties
빈을 포함시키려면 @EnableConfigurationProperties
를 사용하면 된다. (스프링 부트에서 Cassandra를 사용하는 방법은 이 챕터 앞에서 나온 “Cassandra“를 참고해라.)
@DataCassandraTest
로 활성화되는 자동 설정들은 부록에서 확인할 수 있다.
아래 예시는 스프링 부트에서 Cassandra 테스트를 이용하는 전형적인 구성을 보여준다:
@DataCassandraTest
class MyDataCassandraTests {
@Autowired
private SomeRepository repository;
}
Auto-configured Data JPA Tests
JPA 애플리케이션을 테스트할 땐 @DataJpaTest
어노테이션을 사용할 수 있다. 이 어노테이션은 기본적으로 @Entity
클래스를 스캔하고 Spring Data JPA 레포지토리를 구성한다. 클래스패스에 임베디드 데이터베이스가 있으면 임베디드 DB도 구성한다. spring.jpa.show-sql
프로퍼티는 기본적으로 true
로 설정돼서 SQL 쿼리를 로깅한다. 쿼리 로깅은 어노테이션에 있는 showSql()
속성으로 비활성화할 수 있다.
@DataJpaTest
어노테이션을 사용할 땐 전형적인 @Component
와 @ConfigurationProperties
빈은 스캔하지 않는다. @ConfigurationProperties
빈을 포함시키려면 @EnableConfigurationProperties
를 사용하면 된다.
@DataJpaTest
로 활성화되는 자동 설정들은 부록에서 확인할 수 있다.
기본적으로 data JPA 테스트는 트랜잭션을 사용하며, 각 테스트가 끝날 때 롤백을 수행한다. 자세한 내용은 스프링 프레임워크 레퍼런스 문서에서 관련 섹션을 참고해라. 이 동작이 싫다면 다음과 같이 테스트나, 아니면 클래스에 통째로 트랜잭션 관리를 비활성화할 수 있다:
@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyNonTransactionalTests {
// ...
}
Data JPA 테스트에선 TestEntityManager
빈도 주입할 수 있는데, 이 빈은 표준 JPA EntityManager
대신 사용할 수 있는 특별한 테스트 전용 빈이다. TestEntityManager
를 @DataJpaTest
인스턴스 밖에서 사용하고 싶다면 @AutoConfigureTestEntityManager
어노테이션을 사용해도 된다. 필요하면 JdbcTemplate
도 사용할 수 있다. @DataJpaTest
어노테이션을 사용하는 예제는 아래 있다:
@DataJpaTest
class MyRepositoryTests {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository repository;
@Test
void testExample() throws Exception {
this.entityManager.persist(new User("sboot", "1234"));
User user = this.repository.findByUsername("sboot");
assertThat(user.getUsername()).isEqualTo("sboot");
assertThat(user.getEmployeeNumber()).isEqualTo("1234");
}
}
인메모리 임베디드 데이터베이스는 빠르고 설치가 필요 없기 때문에 보통 테스트하기에 좋다. 하지만 실제 데이터베이스로 테스트를 실행하고 싶을 땐, 다음 예제처럼 @AutoConfigureTestDatabase
어노테이션을 사용하면 된다:
@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
class MyRepositoryTests {
// ...
}
Auto-configured JDBC Tests
@JdbcTest
는 @DataJpaTest
와 유사하지만, DataSource
만 필요하고 Spring Data JDBC를 사용하지 않는 테스트에 사용한다. 기본적으로 인메모리 임베디드 데이터베이스와 JdbcTemplate
을 설정한다. @JdbcTest
어노테이션을 사용할 때는 전형적인 @Component
와 @ConfigurationProperties
빈은 스캔하지 않는다. @ConfigurationProperties
빈을 포함시키려면 @EnableConfigurationProperties
를 사용하면 된다.
@JdbcTest
로 활성화되는 자동 설정들은 부록에서 확인할 수 있다.
기본적으로 JDBC 테스트는 트랜잭션을 사용하며, 각 테스트가 끝날 때 롤백을 수행한다. 자세한 내용은 스프링 프레임워크 레퍼런스 문서에서 관련 섹션을 참고해라. 이 동작이 싫다면 다음과 같이 테스트나, 아니면 클래스에 통째로 트랜잭션 관리를 비활성화할 수 있다:
@JdbcTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyTransactionalTests {
}
실제 데이터베이스에서 테스트를 실행하고 싶다면 DataJpaTest
에서와 동일한 방식으로 @AutoConfigureTestDatabase
어노테이션을 사용하면 된다. (“Auto-configured Data JPA Tests” 참고.)
Auto-configured Data JDBC Tests
@DataJdbcTest
는 @JdbcTest
와 유사하지만, Spring Data JDBC를 사용하는 테스트에 사용한다. 기본적으로 인메모리 임베디드 데이터베이스와 JdbcTemplate
, Spring Data JDBC 레포지토리를 설정한다. @DataJdbcTest
어노테이션을 사용할 때는 전형적인 @Component
와 @ConfigurationProperties
빈은 스캔하지 않는다. @ConfigurationProperties
빈을 포함시키려면 @EnableConfigurationProperties
를 사용하면 된다.
@DataJdbcTest
로 활성화되는 자동 설정들은 부록에서 확인할 수 있다.
기본적으로 Data JDBC 테스트는 트랜잭션을 사용하며, 각 테스트가 끝날 때 롤백을 수행한다. 자세한 내용은 스프링 프레임워크 레퍼런스 문서에서 관련 섹션을 참고해라. 이 동작이 싫다면 JDBC 예제에서 보여준대로 테스트나, 아니면 클래스에 통째로 트랜잭션 관리를 비활성화할 수 있다:
실제 데이터베이스에서 테스트를 실행하고 싶다면 DataJpaTest
에서와 동일한 방식으로 @AutoConfigureTestDatabase
어노테이션을 사용하면 된다. (“Auto-configured Data JPA Tests” 참고.)
Auto-configured jOOQ Tests
jOOQ 관련 테스트를 진행할 땐 @JooqTest
를 @JdbcTest
와 비슷한 방식으로 사용하면 된다. jOOQ는 데이터베이스 스키마에 해당하는, 자바 기반 스키마에 크게 의존하기 때문에 기존 DataSource
를 그대로 사용한다. 인메모리 데이터베이스로 교체하려면 @AutoConfigureTestDatabase
를 통해 해당 설정을 재정의할 수 있다. (스프링 부트에서 jOOQ를 사용하는 방법은 이 챕터 앞에 있는 “jOOQ 사용하기“를 참고해라.) @JooqTest
어노테이션을 사용할 때는 전형적인 @Component
와 @ConfigurationProperties
빈은 스캔하지 않는다. @ConfigurationProperties
빈을 포함시키려면 @EnableConfigurationProperties
를 사용하면 된다.
@JooqTest
로 활성화되는 자동 설정들은 부록에서 확인할 수 있다.
@JooqTest
는 DSLContext
를 설정한다. 다음은 @JooqTest
어노테이션을 사용하는 예시다:
@JooqTest
class MyJooqTests {
@Autowired
private DSLContext dslContext;
// ...
}
기본적으로 JOOQ 테스트는 트랜잭션을 사용하며, 각 테스트가 끝날 때 롤백을 수행한다. 이 동작이 싫다면 JDBC 예제에서 보여준대로 테스트나, 아니면 클래스에 통째로 트랜잭션 관리를 비활성화할 수 있다:
Auto-configured Data MongoDB Tests
MongoDB 애플리케이션을 테스트할 땐 @DataMongoTest
를 사용할 수 있다. 이 어노테이션은 기본적으로 인메모리 임베디드 MongoDB를 구성하고 (있으면), MongoTemplate
을 설정하고, @Document
클래스들을 스캔하고, Spring Data MongoDB 레포지토리를 구성한다. @DataMongoTest
어노테이션을 사용할 때는 전형적인 @Component
와 @ConfigurationProperties
빈은 스캔하지 않는다. @ConfigurationProperties
빈을 포함시키려면 @EnableConfigurationProperties
를 사용하면 된다. (스프링 부트에서 MongoDB를 사용하는 방법은 이 챕터 앞에 있는 “MongoDB“를 참고해라.)
@DataMongoTest
로 활성화되는 자동 설정들은 부록에서 확인할 수 있다.
아래 클래스는 @DataMongoTest
어노테이션을 사용하는 모습을 보여준다:
@DataMongoTest
class MyDataMongoDbTests {
@Autowired
private MongoTemplate mongoTemplate;
// ...
}
인메모리 임베디드 MongoDB는 빠르고 개발자 설치가 필요 없기 때문에 보통 테스트하기에 좋다. 하지만 실제 MongoDB 서버로 테스트를 실행하고 싶을 땐, 아래 예제처럼 임베디드 MongoDB 자동 설정을 제외시켜야 한다:
@DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
class MyDataMongoDbTests {
// ...
}
Auto-configured Data Neo4j Tests
Neo4j 애플리케이션을 테스트할 땐 @DataNeo4jTest
를 사용할 수 있다. 이 어노테이션은 기본적으로 @Node
클래스들을 스캔하고, Spring Data Neo4j 레포지토리를 구성한다. @DataNeo4jTest
어노테이션을 사용할 때는 전형적인 @Component
와 @ConfigurationProperties
빈은 스캔하지 않는다. @ConfigurationProperties
빈을 포함시키려면 @EnableConfigurationProperties
를 사용하면 된다. (스프링 부트에서 Neo4J를 사용하는 방법은 이 챕터 앞에 있는 “Neo4j“를 참고해라.)
@DataNeo4jTest
로 활성화되는 자동 설정들은 부록에서 확인할 수 있다.
아래 예시는 스프링 부트에서 Neo4J 테스트를 이용하는 전형적인 구성을 보여준다:
@DataNeo4jTest
class MyDataNeo4jTests {
@Autowired
private SomeRepository repository;
// ...
}
기본적으로 Data Neo4j 테스트는 트랜잭션을 사용하며, 각 테스트가 끝날 때 롤백을 수행한다. 자세한 내용은 스프링 프레임워크 레퍼런스 문서에서 관련 섹션을 참고해라. 이 동작이 싫다면 테스트나, 아니면 아래처럼 클래스에 통째로 트랜잭션 관리를 비활성화할 수 있다:
@DataNeo4jTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
class MyDataNeo4jTests {
}
리액티브로 접근할 때는 트랜잭션 테스트를 지원하지 않는다. 리액티브 스타일을 사용하고 있다면
@DataNeo4jTest
테스트를 바로 위에서 설명하는 대로 설정해야 한다.
Auto-configured Data Redis Tests
Redis 애플리케이션을 테스트할 땐 @DataRedisTest
를 사용할 수 있다. 이 어노테이션은 기본적으로 @RedisHash
클래스들을 스캔하고, Spring Data Redis 레포지토리를 구성한다. @DataRedisTest
어노테이션을 사용할 때는 전형적인 @Component
와 @ConfigurationProperties
빈은 스캔하지 않는다. @ConfigurationProperties
빈을 포함시키려면 @EnableConfigurationProperties
를 사용하면 된다. (스프링 부트에서 Redis를 사용하는 방법은 이 챕터 앞에 있는 “Redis“를 참고해라.)
@DataRedisTest
로 활성화되는 자동 설정들은 부록에서 확인할 수 있다.
다음은 @DataRedisTest
어노테이션을 사용하는 예시다:
@DataRedisTest
class MyDataRedisTests {
@Autowired
private SomeRepository repository;
// ...
}
Auto-configured Data LDAP Tests
LDAP 애플리케이션을 테스트할 땐 @DataLdapTest
를 사용할 수 있다. 이 어노테이션은 기본적으로 인메모리 임베디드 LDAP을 구성하고 (있으면), LdapTemplate
을 설정하고, @Entry
클래스들을 스캔하고, Spring Data LDAP 레포지토리를 구성한다. @DataLdapTest
어노테이션을 사용할 때는 전형적인 @Component
와 @ConfigurationProperties
빈은 스캔하지 않는다. @ConfigurationProperties
빈을 포함시키려면 @EnableConfigurationProperties
를 사용하면 된다. (스프링 부트에서 LDAP을 사용하는 방법은 이 챕터 앞에 있는 “LDAP“을 참고해라.)
@DataLdapTest
로 활성화되는 자동 설정들은 부록에서 확인할 수 있다.
다음은 @DataLdapTest
어노테이션을 사용하는 예시다:
@DataLdapTest
class MyDataLdapTests {
@Autowired
private LdapTemplate ldapTemplate;
// ...
}
인메모리 임베디드 LDAP은 빠르고 개발자 설치가 필요 없기 때문에 보통 테스트하기에 좋다. 하지만 실제 LDAP 서버로 테스트를 실행하고 싶을 땐, 아래 예제처럼 임베디드 LDAP 자동 설정을 제외시켜야 한다:
@DataLdapTest(excludeAutoConfiguration = EmbeddedLdapAutoConfiguration.class)
class MyDataLdapTests {
// ...
}
Auto-configured REST Clients
REST 클라이언트를 테스트할 땐 @RestClientTest
를 사용할 수 있다. 이 어노테이션은 기본적으로 Jackson, GSON, Jsonb 지원을 자동 설정하고, RestTemplateBuilder
를 설정하고, MockRestServiceServer
지원을 위한 기능들을 추가한다. @RestClientTest
어노테이션을 사용할 때는 전형적인 @Component
와 @ConfigurationProperties
빈은 스캔하지 않는다. @ConfigurationProperties
빈을 포함시키려면 @EnableConfigurationProperties
를 사용하면 된다.
@RestClientTest
로 활성화되는 자동 설정들은 부록에서 확인할 수 있다.
테스트하려는 빈은 다음 예제처럼 @RestClientTest
의 value
또는 components
속성을 사용해서 지정해줘야 한다:
@RestClientTest(RemoteVehicleDetailsService.class)
class MyRestClientTests {
@Autowired
private RemoteVehicleDetailsService service;
@Autowired
private MockRestServiceServer server;
@Test
void getVehicleDetailsWhenResultIsSuccessShouldReturnDetails() throws Exception {
this.server.expect(requestTo("/greet/details")).andRespond(withSuccess("hello", MediaType.TEXT_PLAIN));
String greeting = this.service.callRestService();
assertThat(greeting).isEqualTo("hello");
}
}
Auto-configured Spring REST Docs Tests
Mock MVC나, REST Assured, WebTestClient를 사용하는 테스트에선 @AutoConfigureRestDocs
어노테이션을 통해 스프링 REST Docs를 사용할 수 있다. Spring REST Docs에선 JUnit 익스텐션이 없어도 된다.
@AutoConfigureRestDocs
로는 디폴트 출력 디렉토리(메이븐을 사용한다면 target/generated-snippets
, 또는 그래들에선 build/generated-snippets
)를 재정의할 수 있다. 더불어 URI를 문서화할 때 사용할 호스트, 스킴, 포트도 설정할 수 있다.
Auto-configured Spring REST Docs Tests with Mock MVC
@AutoConfigureRestDocs
는 서블릿 기반 웹 애플리케이션을 테스트할 땐 MockMvc
빈을 커스텀해서 Spring REST Docs를 사용하도록 만든다. MockMvc
는 다음 예제처럼 @Autowired
를 사용해 테스트에 주입하고 활용할 수 있다. 평상시 Mock MVC와 Spring REST Docs를 사용할 때와 동일하다:
@WebMvcTest(UserController.class)
@AutoConfigureRestDocs
class MyUserDocumentationTests {
@Autowired
private MockMvc mvc;
@Test
void listUsers() throws Exception {
this.mvc.perform(get("/users").accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andDo(document("list-users"));
}
}
Spring REST Docs 설정을 @AutoConfigureRestDocs
속성으로 제공하는 것 이상으로 더 제어하고 싶으면, 아래 예제처럼 RestDocsMockMvcConfigurationCustomizer
빈을 사용하면 된다:
@TestConfiguration(proxyBeanMethods = false)
public class MyRestDocsConfiguration implements RestDocsMockMvcConfigurationCustomizer {
@Override
public void customize(MockMvcRestDocumentationConfigurer configurer) {
configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
}
}
Spring REST Docs에서 지원하는 대로 출력 디렉토리에 파라미터를 활용하고 싶다면 RestDocumentationResultHandler
빈을 생성하면 된다. 자동 설정에선 이 Result 핸들러를 넘겨 alwaysDo
를 호출하므로, MockMvc
를 호출할 때마다 자동으로 디폴트 스니펫을 생성한다. 다음은 RestDocumentationResultHandler
를 정의하는 예시다:
@TestConfiguration(proxyBeanMethods = false)
public class MyResultHandlerConfiguration {
@Bean
public RestDocumentationResultHandler restDocumentation() {
return MockMvcRestDocumentation.document("{method-name}");
}
}
Auto-configured Spring REST Docs Tests with WebTestClient
@AutoConfigureRestDocs
는 WebTestClient
와 함께 사용해서 리액티브 웹 애플리케이션을 테스트할 수도 있다. WebTestClient
는 다음 예제처럼 @Autowired
를 사용해 테스트에 주입하고 활용할 수 있다. 평상시 @WebFluxTest
와 Spring REST Docs를 사용할 때와 동일하다:
@WebFluxTest
@AutoConfigureRestDocs
class MyUsersDocumentationTests {
@Autowired
private WebTestClient webTestClient;
@Test
void listUsers() {
this.webTestClient
.get().uri("/")
.exchange()
.expectStatus()
.isOk()
.expectBody()
.consumeWith(document("list-users"));
}
}
Spring REST Docs 설정을 @AutoConfigureRestDocs
속성으로 제공하는 것 이상으로 더 제어하고 싶으면, 아래 예제처럼 RestDocsWebTestClientConfigurationCustomizer
빈을 사용하면 된다:
@TestConfiguration(proxyBeanMethods = false)
public class MyRestDocsConfiguration implements RestDocsWebTestClientConfigurationCustomizer {
@Override
public void customize(WebTestClientRestDocumentationConfigurer configurer) {
configurer.snippets().withEncoding("UTF-8");
}
}
Auto-configured Spring REST Docs Tests with REST Assured
@AutoConfigureRestDocs
는 RequestSpecification
을 미리 만들어 Spring REST Docs를 사용하도록 미리 설정해두기 때문에 RequestSpecification
도 테스트에 활용할 수 있다. RequestSpecification
은 다음 예제처럼 @Autowired
를 사용해 테스트에 주입하고 활용할 수 있다. 평상시 REST Assured와 Spring REST Docs를 사용할 때와 동일하다:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureRestDocs
class MyUserDocumentationTests {
@Test
void listUsers(@Autowired RequestSpecification documentationSpec, @LocalServerPort int port) {
given(documentationSpec)
.filter(document("list-users"))
.when()
.port(port)
.get("/")
.then().assertThat()
.statusCode(is(200));
}
}
Spring REST Docs 설정을 @AutoConfigureRestDocs
속성으로 제공하는 것 이상으로 더 제어하고 싶으면, 아래 예제처럼 RestDocsRestAssuredConfigurationCustomizer
빈을 사용하면 된다:
@TestConfiguration(proxyBeanMethods = false)
public class MyRestDocsConfiguration implements RestDocsRestAssuredConfigurationCustomizer {
@Override
public void customize(RestAssuredRestDocumentationConfigurer configurer) {
configurer.snippets().withTemplateFormat(TemplateFormats.markdown());
}
}
Auto-configured Spring Web Services Tests
Spring Web Services 프로젝트를 통해 웹 서비스를 호출하는 애플리케이션을 테스트할 땐 @WebServiceClientTest
를 사용할 수 있다. 이 어노테이션은 기본적으로 mock WebServiceServer
빈을 구성하고, WebServiceTemplateBuilder
를 자동으로 커스텀해준다. (스프링 부트에서 웹 서비스를 사용하는 방법은 이 챕터 앞에 있는 “웹 서비스“를 참고해라.)
@WebServiceClientTest
로 활성화되는 자동 설정들은 부록에서 확인할 수 있다.
다음은 @WebServiceClientTest
어노테이션을 사용하는 예시다:
@WebServiceClientTest(SomeWebService.class)
class MyWebServiceClientTests {
@Autowired
private MockWebServiceServer server;
@Autowired
private SomeWebService someWebService;
@Test
void mockServerCall() {
this.server
.expect(payload(new StringSource("<request/>")))
.andRespond(withPayload(new StringSource("<response><status>200</status></response>")));
assertThat(this.someWebService.test())
.extracting(Response::getStatus)
.isEqualTo(200);
}
}
Additional Auto-configuration and Slicing
각 슬라이스마다 @AutoConfigure…
어노테이션을 하나 이상 제공하는데, 이 어노테이션으로는 말그대로 슬라이스에 포함시켜야 하는 자동 설정을 정의할 수 있다. 커스텀 @AutoConfigure…
어노테이션을 생성하거나 아래 예제처럼 @ImportAutoConfiguration
을 테스트에 추가하면, 테스트마다 별도로 필요한 자동 설정을 더 추가할 수 있다:
@JdbcTest
@ImportAutoConfiguration(IntegrationAutoConfiguration.class)
class MyJdbcTests {
}
일반
@Import
어노테이션으로 자동 설정을 임포트하지 않도록 주의해라. 자동 설정은 스프링 부트에서 별도 방식으로 다르게 처리한다.
아니면 아래 예제처럼 META-INF/spring.factories
에 등록해도 슬라이스 어노테이션을 사용할 때 쓸 별도 자동 설정들을 추가할 수 있다:
org.springframework.boot.test.autoconfigure.jdbc.JdbcTest=com.example.IntegrationAutoConfiguration
슬라이스나
@AutoConfigure…
어노테이션은@ImportAutoConfiguration
을 메타 어노테이션으로 선언만 해주면 이런식으로 커스텀할 수 있다.
User Configuration and Slicing
베스트 프랙티스에 따라 코드 구조를 잡으면 기본적으로 @SpringBootApplication
클래스를 테스트 설정으로 사용한다.
이렇게 되면 중요한 건 애플리케이션의 메인 클래스에, 특정 기능에서만 필요한 설정을 두지 않는 거다.
스프링 배치를 사용 중이고 자동 설정에 의존한다고 가정해보자. 다음과 같이 @SpringBootApplication
을 정의할 수 있다:
@SpringBootApplication
@EnableBatchProcessing
public class MyApplication {
// ...
}
테스트는 이 클래스에서 설정을 가져오기 때문에, 실제로 모든 슬라이스 테스트가 스프링 배치를 시작하려고 하지만, 이는 분명히 원하는 바가 아니다. 다음 예제처럼 특정한 영역에 속하는 설정은 애플리케이션과 동일한 레벨에 있는 별도 @Configuration
클래스로 이동하는 게 좋다:
@Configuration(proxyBeanMethods = false)
@EnableBatchProcessing
public class MyBatchConfiguration {
// ...
}
애플리케이션의 복잡성에 따라 커스텀을 위한
@Configuration
클래스가 딱 하나 있을 수도 있고, 도메인 영역마다 클래스가 하나씩 있을 수도 있다. 후자에선 필요하면@Import
어노테이션으로 테스트에 활성화해줄 수 있다.
테스트 슬라이스는 @Configuration
클래스는 제외하고 스캔한다. @WebMvcTest
로 예를 들면, 아래 설정에서 보이는 WebMvcConfigurer
빈은 테스트 슬라이스로 로드하는 애플리케이션 컨텍스트에는 추가되지 않을 거다:
@Configuration(proxyBeanMethods = false)
public class MyWebConfiguration {
@Bean
public WebMvcConfigurer testConfigurer() {
return new WebMvcConfigurer() {
// ...
};
}
}
하지만 아래 설정에선 테스트 슬라이스는 커스텀 WebMvcConfigurer
를 로드한다.
@Component
public class MyWebMvcConfigurer implements WebMvcConfigurer {
// ...
}
또 하나 헷갈릴 수 있는 건 클래스패스 스캔이다. 코드 구조는 합리적으로 짰지만, 별도의 패키지를 스캔해야 한다고 가정해보자. 애플리케이션은 다음 코드와 유사할 거다:
@SpringBootApplication
@ComponentScan({ "com.example.app", "com.example.another" })
public class MyApplication {
// ...
}
이렇게 하면 사실상 디폴트 컴포넌트 스캔 지시문을 재정의해서, 슬라이스로 뭘 선택했든지 간에 두 패키지를 스캔하는 부작용을 낳는다. 예를 들어 @DataJpaTest
에서는 갑자기 애플리케이션의 컴포넌트와 사용자 설정을 스캔하는 것으로 보일 거다. 다시 말하지만, 커스텀 지시문은 별도의 클래스로 이동시키는 게 이 문제를 해결할 수 있는 길이다.
이게 불가능하다면, 테스트 계층구조 어딘가에
@SpringBootConfiguration
을 하나 만들어놓고 대신 사용해도 된다. 아니면 테스트에서 가져올 설정을 지정해서 디폴트 설정을 찾는 동작을 비활성화해도 된다.
Using Spock to Test Spring Boot Applications
스프링 부트 애플리케이션을 테스트할 땐 Spock 2.x를 사용할 수 있다. 먼저 Spock의 spock-spring
모듈 의존성을 애플리케이션 빌드에 추가해라. spock-spring
은 스프링의 테스트 프레임워크를 Spock에 통합해준다. 자세한 내용은 Spock 문서에서 스프링 모듈을 확인해봐라.
7.26.4. Test Utilities
애플리케이션 테스트에 유용할만한 몇 가지 테스트 유틸리티 클래스들은 spring-boot
에 패키징되어 있다.
ConfigDataApplicationContextInitializer
ConfigDataApplicationContextInitializer
는 테스트에서 스프링 부트 application.properties
파일을 로드할 수 있는 ApplicationContextInitializer
다. 아래처럼 @SpringBootTest
에서 제공하는 기능 셋이 전부 필요하진 않을 때 사용할 수 있다:
@ContextConfiguration(classes = Config.class, initializers = ConfigDataApplicationContextInitializer.class)
class MyConfigFileTests {
// ...
}
ConfigDataApplicationContextInitializer
만 단독으로 사용하면@Value("${…}")
주입은 지원하지 않는다. 유일하게 수행하는 작업은application.properties
파일을 스프링의Environment
에 로드하는 거다.@Value
를 사용하려면 별도로PropertySourcesPlaceholderConfigurer
를 설정하거나, 자동으로 설정해주는@SpringBootTest
를 사용해야 한다.
TestPropertyValues
TestPropertyValues
를 사용하면 ConfigurableEnvironment
나 ConfigurableApplicationContext
에 프로퍼티를 재빠르게 추가할 수 있다. 다음과 같이 key=value
문자열 조합으로 호출하면 된다:
class MyEnvironmentTests {
@Test
void testPropertySources() {
MockEnvironment environment = new MockEnvironment();
TestPropertyValues.of("org=Spring", "name=Boot").applyTo(environment);
assertThat(environment.getProperty("name")).isEqualTo("Boot");
}
}
OutputCapture
OutputCapture
는 System.out
과 System.err
출력을 캡처할 수 있는 JUnit Extension
이다. 다음과 같이 @ExtendWith(OutputCaptureExtension.class)
를 추가하고 CapturedOutput
을 테스트 클래스 생성자나 테스트 메소드 인자로 주입해라:
@ExtendWith(OutputCaptureExtension.class)
class MyOutputCaptureTests {
@Test
void testName(CapturedOutput output) {
System.out.println("Hello World!");
assertThat(output).contains("World");
}
}
TestRestTemplate
TestRestTemplate
은 통합 테스트에서 스프링의 RestTemplate
대신 좀 더 간편하게 사용할 수 있는 템플릿이다. 순수vanilla 템플릿이나 Basic HTTP 인증(username과 password로)을 전송하는 템플릿을 가져올 수 있다. 이 템플릿은 두 경우 모두 내결함성fault tolerance을 지원한다. 즉, 4xx, 5xx 에러에서 예외를 발생시키지 않고 테스트 친화적인 방식으로 동작한다. 그대신 반환하는 ResponseEntity
와, 여기에 들어 있는 상태 코드를 통해 에러를 판단하면 된다.
스프링 프레임워크 5.0은 WebFlux 통합 테스트와 WebFlux, MVC end-to-end 테스트에 모두 활용할 수 있는 새로운
WebTestClient
를 제공한다.WebTestClient
는TestRestTemplate
과는 달리 assertion을 위한 fluent API를 제공한다.
아파치 HTTP 클라이언트(4.3.2 이상)를 사용하는 걸 권장하지만, 필수는 아니다. 아파치 HTTP 클라이언트가 클래스패스에 있으면 TestRestTemplate
은 이 클라이언트를 적당히 설정해서 응답해준다. 아파치의 HTTP 클라이언트를 사용하게 되면 테스트 친화적인 기능들이 몇 가지가 더 활성화된다:
- 리다이렉션을 따르지 않는다 (따라서 응답 위치를 검증할 수 있다).
- 쿠키를 무시한다 (따라서 템플릿엔 상태가 없다stateless).
TestRestTemplate
은 아래 예제처럼 통합 테스트 안에서 직접 인스턴스를 만들어도 된다:
class MyTests {
private TestRestTemplate template = new TestRestTemplate();
@Test
void testRequest() throws Exception {
ResponseEntity<String> headers = this.template.getForEntity("https://myhost.example.com/example", String.class);
assertThat(headers.getHeaders().getLocation()).hasHost("other.example.com");
}
}
아니면 @SpringBootTest
어노테이션으로 WebEnvironment.RANDOM_PORT
나 WebEnvironment.DEFINED_PORT
를 지정하면, 완전한 설정을 갖춘 TestRestTemplate
을 주입하고 바로 사용할 수 있다. 필요하면 RestTemplateBuilder
빈으로 별도 커스텀을 적용할 수 있다. 아래 예제처럼 URL에 호스트와 포트를 지정하지 않으면 전부 자동으로 임베디드 서버에 연결된다:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MySpringBootTests {
@Autowired
private TestRestTemplate template;
@Test
void testRequest() {
HttpHeaders headers = this.template.getForEntity("/example", String.class).getHeaders();
assertThat(headers.getLocation()).hasHost("other.example.com");
}
@TestConfiguration(proxyBeanMethods = false)
static class RestTemplateBuilderConfiguration {
@Bean
RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder().setConnectTimeout(Duration.ofSeconds(1))
.setReadTimeout(Duration.ofSeconds(1));
}
}
}
Next :WebSockets
스프링 부트로 웹소켓 자동 설정하기
전체 목차는 여기에 있습니다.