본문 바로가기
  • 실행력이 모든걸 결정한다
Spring Series/Document

[SpringBoot] 공식 문서 요약(3) - Testing

by 김코더 김주역 2021. 11. 3.
반응형

SpringBoot Document Review 3

https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/reference/html/

 

 

Testing

https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/reference/html/boot-features-testing.html

 

1) Test Scope Dependencies

- spring-boot-starter-test라는 Starter는 Spring Boot 테스트 모듈과 다른 테스팅 라이브러리들을 지원한다.

※ scope은 일반적으로 <scope>test<scope>로 적용하며, 기능들을 src/test 에서만 사용할 수 있다는 뜻이다.

 

 

2) Test Spring Applications

- 모의 객체(Mock Object) : 개발한 프로그램을 테스트 할 경우 테스트를 수행할 모듈과 연결되는 외부의 다른 서비스나 모듈들을 실제 사용하는 모듈을 사용하지 않고 실제의 모듈을 흉내내는 가짜 모듈을 작성하여 테스트의 효용성을 높이는데 사용하는 객체

- 배포할 필요 없이 통합 테스팅을 수행하는데 유용한 테스트 모듈을 지원한다.

 

 

3) Test Spring Boot Applications

(1) 기본 소개

- src/main/java에 있는 패키지와 동일한 이름의 패키지를 src/test/java에 생성해주고 테스트 클래스를 생성한다.

- spring-test의 @ContextConfiguration 대신 @SpringBootTest를 사용할 수 있다.

- @SpringBootTest의 인자로 webEnvironment 속성을 적용하여 다양한 테스트를 실행할 수 있다. 기본값인 MOCK 옵션의 경우에는 mock 서블릿 환경을 제공해주고 Embedded servlet container는 작동하지 않기 때문에, 커스터마이징한 servlet은 src/test에서는 적용되지 않는다. 그리고 RANDOM_PORT, DEFINED_PORT 옵션은 실제 서블릿 환경을 제공해준다. (더 자세한 속성값은 문서 참고)

- @SpringBootTest(properties="spring.main.web-application-type=reactive") 속성으로 반응형 웹을 테스트할 수 있다.

- @Transactional 테스트는 일반적으로 각 테스트 메소드가 끝날 때 트랜잭션이 롤백되는데, RANDOM_PORT, DEFINED_PORT 방식에서는 롤백되지 않는다.

- @SpringBootTest 클래스에 @RunWith(SpringRunner.class)를 추가하지 않으면 다른 어노테이션들이 무시될 것이다.

- 테스트 메소드에는 @Test 어노테이션을 붙여야 한다.

 

(2) Web Application Type 탐지 제공

- MVC를 사용한다면 MVC 기반의 application context가 설정되고, WebFlux를 사용한다면 WebFlux 기반의 application context가 설정된다. 우선 순위는 MVC가 더 높다.

 

(3) Test Configuration 탐지 제공

- Spring Boot에서 테스트를 할 때에는 굳이 @Configuration클래스의 위치를 @ContextConfiguration(classes=...)에 명시해주거나, test안에서 @Configuration클래스를 사용하지 않아도 된다. 대신 @*Test 어노테이션을 붙여서 설정 파일들을 알아서 찾게 해주면 된다.

- 일부분만 따로 테스트하고 싶다면, main메소드가 있는 클래스에 configuration 설정을 추가하는 것은 자제해야 한다.

- @SpringBootTest에서 @TestConfiguration 내부 클래스를 사용한다면, 설정이 애플리케이션의 기본 설정에 추가된다. 반면에 @Configration 내부 클래스를 사용한다면, 애플리케이션의 기본 설정을 자신이 대체함으로써 자신이 메인 설정이 되기 때문에 다른 Bean들이 무시될 수 있다.

※ 이들을 내부 클래스로 두지 않으면 스캔 대상에서 제외된다.

※ @TestConfiguration 내부 클래스는 static으로 둔다.

- Spring의 Test Framework는 application context를 캐싱하기 때문에, 같은 Bean 설정 파일을 쓰는 Test들끼리 재사용할 수 있다.

※ Application context : Application의 상태를 포함하고 있는 정보의 접근을 제공

 

(4) Text Configuration 제외하기

- 만약 애플리케이션에서 component scanning을 사용하고 있다면(@SpringBootApplication, @ComponentScan 등), 특정 테스트를 위해 만들어둔 Configuration 클래스들이 어딘가에서 선택될 수 있다.

- @TestConfiguration 클래스를 내부 클래스로 두지 않았다면 src/test/java에서 스캔되지 않는다. 대신, @Import 어노테이션을 이용하면 이 @TestConfiguration 클래스를 개별적으로 호출할 수 있다.

- @SpringBootApplication이 아닌 @ComponentScan을 직접 사용한다면 TypeExcludeFilter을 등록해야 한다.

 

(5) running 서버 테스트하기

https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-with-running-server

- 이 경우에는 @SpringBootTest의 webEnvironment 속성값으로 RANDOM_PORT를 주는 것을 권장한다. 랜덤 포트는 @LocalServerPort으로 가져올 수 있다.

- REST 요청 테스트 : WebFlux 환경에서는 WebTestClient 객체를, Spring MVC 환경에서는 TestRestTemplate 객체를 @Autowired로 받아와서 사용하면 된다. 각각의 예제는 위 링크에서 확인할 수 있다.

※ TestRestTemplate 객체는 WebFlux 환경에서도 @autowired로 받을 수 있다.

 

(6) Mocking and Spying Beans

- 실제 환경에서 발생하기 어려운 예외 케이스를 시뮬레이션하기에 유용하다.

- 개발자는 MockBean, SpyBean의 어떤 메소드를 대상으로 입력값에 따른 리턴값을 조작하면서 테스트할 수 있게 된다.

- 테스트 클래스에서 @MockBean을 이용하여 구현이 안된 새로운 모의 Bean을 추가하거나 이름을 강제 지정하고 교체할 수 있다.

- @MockBean은 given에서 선언한 코드 외에는 전부 사용할 수 없다.

- 기본적인 Mocking 방식은 일반적으로 테스트 Annotation에 자동 세팅되어 있는데, 다른 방식으로 따로 설정하고 싶다면 @TestExecutionListeners를 사용하면 된다.

- 테스트 클래스에서 @SpyBean을 이용하여 기존의 bean을 SpyBean으로 감싸줄 수 있다.

- @SpyBean은 given에서 선언한 코드 외에는 전부 실제 객체의 것을 사용한다.

- @SpyBean은 test에서 한 클래스당 하나씩 생성할 수 있다.

- @MockBean, @SpyBean을 사용하면 테스트마다 Application context를 생성한다. 원래 Spring에서는 테스트마다 Applicatoin context를 캐싱해두고 같은 설정을 공유하는 테스트에서는 context를 재사용한다.

 

(7) Auto-configured Tests

- 테스트의 일부(slicing)에 대한 설정 부분만 로드하고 싶을 때 사용된다.

- spring-boot-test-autoconfigure 모듈은 여러 Test 어노테이션들과 여러 AutoConfigure 어노테이션들을 제공한다.

※ AutoConfigure 어노테이션들을 @SpringBootTest에 적용함으로써 slicing을 적용하지 않을 수도 있다.

- Test 어노테이션들은 excludeAutoConfiguration 속성이나 @ImportAutoConfiguration#exclude 어노테이션을 제공하여 일부 설정을 배제할 수 있도록 한다.

 

(8) Auto-configured JSON Tests

- @JsonTest으로 JSON의 직렬화/역직렬화를 테스트할 수 있으며, 사용 가능한 JSON mapper으로 자동 설정해준다.

※ JSON mapper libraries : Jackson, Gson, Jsonb

- @AutoConfigureJsonTesters : auto-configuration되는 요소들을 재설정

- @JsonTest를 사용하면 JacksonTester, GsonTester, JsonbTester, BasicJsonTester같은 JSON helper클래스의 helper field들을 @Autowired로 가져올 수 있다.

- @JsonTest를 사용하지 않고 인스턴스를 직접 생성하는 경우에는, @Before 메소드의 내부에서 JSON helper의 initFields 메소드를 호출해서 사용할 수 있다. 이 방법은 Json만 테스트할 경우에 사용할 수 있고, 매우 빠르다.

예제

@RunWith(SpringRunner.class)
@JsonTest
public class SampleJsonTest{
    @Autowired
    JacksonTester<Sample> sampleJsonTester;
    
    //@RunWith, @JsonTest, @Autowired을 사용하지 않는다면
    /*
    @Before
    public void setup(){
    	JacksonTester.initFields(this, new ObjectMapper()); //모든 tester들을 instantiate
    }
    */
    
    @Test
    public void testJson() throws IOException{
    	Sample sample = new Sample();
        sample.setName("jooyeok");
        sample.setAge("24");
        
        assertThat(this.sampleJsonTester.write(sample))
            .hasJsonPathStringValue("@.name")
            .extractingJsonPathStringValue("@.name").isEqualTo("jooyeok");
        assertThat(this.sampleJsonTester.write(sample))
            .hasJsonPathNumberValue("@.age")
            .extractingJsonPathNumberValue("@.age").isEqualTo("24");
    }
}

 

(9) Auto-configured Spring MVC Tests

https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc-tests

- @WebMvcTest 어노테이션으로 MVC Controller들이 잘 동작하는지 확인할 수 있다. 단, 이 어노테이션을 사용하면 - 일반적인 Component Bean들은 불러오지 않는다. 추가적인 설정들은 @Import를 이용하여 추가하면 된다.

※ 스캔되는 어노테이션 및 Bean 목록은 문서 참조

- @WebMvcTest는 단일 컨트롤러를 대상으로 테스트하는 용도이며, @MockBean과 같이 사용할 수 있다.

- @WebMvcTest는 MockMvc를 자동 설정한다. Mock MVC는 전체 HTTP 서버를 구동할 필요 없는 빠른 MVC 컨트롤러 테스트 방식을 제공한다.

- @AutoConfigureMockMvc를 사용하면 MockMvc를 non-@WebMvcTest 환경에서도 쓸 수 있다. 또, auto-configure된 요소들을 재설정할 수도 있다.

- HtmlUnit이나 Selenium을 사용하면 auto-configuration은 WebClient bean과 WebDriver bean을 제공한다. WebDriver을 싱글톤으로 주고 싶다면 WebDriver @Bean에 @Scope("singleton")을 붙이면 된다.

 

(10) Auto-configured Spring WebFlux Tests

https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-with-running-server

- @WebFluxTest 어노테이션으로 WebFlux 컨트롤러가 잘 동작하는지 확인할 수 있다. 단, 이 어노테이션을 사용하면 일반적인 Component Bean들은 스캔되지 않는다. 추가적인 설정들은 @Import를 이용하여 추가하면 된다.

- @WebFluxTest는 단일 컨트롤러를 대상으로 테스트하는 용도이며, @MockBean과 같이 사용할 수 있다.

- @WebFluxTest는 WebTestClient를 설정한다. WebTestClient는 전체 HTTP 서버를 구동할 필요 없는 빠른 WebFlux 컨트롤러 테스트 방식을 제공한다.

- @AutoConfigureWebTestClient는 WebTestClient를 autowired 할 수 있게 해주며, non-@WebFluxTest 환경에서도 쓸 수 있다.

 

(11) Auto-configured Data JPA Tests

- @DataJpaTest를 사용하여 JPA 어플리케이션을 테스트할 수 있다.

- 일반적인 Component Bean들은 불러오지 않는다.

- 기본적으로 in-memory 내장형 데이터베이스와 Spring Data JPA repository를 설정하고, @Entity 클래스들을 스캔한다. in-memory 내장형 데이터베이스는 속도가 빠르고 별도의 설치도 필요하지 않다. 그런데 만약 실제 외부 데이터베이스로 테스트하고 싶다면 @DataJpaTest 클래스에 @AutoConfigureTestDatabase(replace=Replace.NONE)를 같이 적용하면 된다.

- 기본적으로 트랜잭션 기반이고, 테스트가 끝날 때마다 롤백된다. 트랜잭션을 원하지 않는다면 @DataJpaTest 클래스에 @Transactional(propagation=Propagation.NOT_SUPPORTED)를 같이 붙여주면 된다.

- 테스트에 특화된 TestEntityManager bean을 주입 받을 수도 있다. 만약 이를 @DataJpaTest 인스턴스 밖에서 사용하고 싶다면 @AutoConfigureTestEntityManager을 사용하면 되고, JdbcTemplate도 적용 가능하다.

 

(12) Auto-configured JDBC Tests

- @JdbcTest는 @DataJpaTest와 비슷하지만, 더 순수하게 JDBC와 관련된 테스트이다.

- 일반적인 Component Bean들은 불러오지 않는다.

- 기본적으로 in-memory 내장형 데이터베이스와 JdbcTemplate을 설정한다. 만약 실제 외부 데이터베이스로 테스트하고 싶다면 @JdbcTest 클래스에 @AutoConfigureTestDatabase(replace=Replace.NONE)를 같이 적용하면 된다.

- 기본적으로 트랜잭션 기반이고, 테스트가 끝날 때마다 롤백된다. 트랜잭션을 원하지 않는다면 @JdbcTest 클래스에 @Transactional(propagation=Propagation.NOT_SUPPORTED)를 같이 붙여주면 된다.

 

(13) Auto-configured jOOQ(Java Object Oriented Querying) Tests

- @JooqTest는 @JdbcTest와 비슷하지만, 더 순수하게 jOOQ와 관련된 테스트이다.

- 일반적인 Component Bean들은 불러오지 않는다.

- jOOQ는 데이터베이스 스키마와 부합하는 Java 기반 스키마에 크게 의존하며, 기존의 DataSource가 사용된다. in-memory 내장형 데이터베이스로 교체하고 싶다면, 단순히 @AutoConfigureTestDatabase를 사용하면 된다.

- @JooqTest는 DSLContext를 설정한다.

- 기본적으로 트랜잭션 기반이고, 테스트가 끝날 때마다 롤백된다. 트랜잭션을 원하지 않는다면 @JooqTest 클래스에 @Transactional(propagation=Propagation.NOT_SUPPORTED)를 같이 붙여주면 된다.

 

(14) Auto-configured Data MongoDB Tests

- @DataMongoTest를 사용하여 MongoDB 어플리케이션을 테스트할 수 있다.

- 일반적인 Component Bean들은 불러오지 않는다.

- 기본적으로 in-memory 내장형 MongoDB, Spring Data MongoDB repository들, 그리고 MongoTemplate를 설정하며, @Document 클래스들을 스캔한다.

- 만약 실제 MongoDB 서버로 테스트하고 싶다면, 테스트 클래스에 @DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)를 적용하면 된다.

 

(15) Auto-configured Data Neo4j Tests

- @DataNeo4jTest를 사용하여 Neo4j 어플리케이션을 테스트할 수 있다.

- 일반적인 Component Bean들은 불러오지 않는다.

- 기본적으로 Spring Data Neo4j repository들을 설정하며, @NodeEntity 클래스들을 스캔한다.

- 기본적으로 내장 드라이버가 있다면 in-memory 내장형 Neo4j를 사용하고, 내장 드라이버가 없다면 실제 Neo4j로 테스트 가능하다.

- 기본적으로 트랜잭션 기반이고, 테스트가 끝날 때마다 롤백된다. 트랜잭션을 원하지 않는다면 @DataNeo4jTest 클래스에 @Transactional(propagation=Propagation.NOT_SUPPORTED)를 같이 붙여주면 된다.

 

(16) Auto-configured Data Redis Tests

- @DataRedisTest를 사용하여 Redis 어플리케이션을 테스트할 수 있다.

- 일반적인 Component Bean들은 불러오지 않는다.

- 기본적으로 Spring Data Redis repository들을 설정하며, @RedisHash 클래스들을 스캔한다.

 

(17) Auto-configured Data LDAP Tests

- @DataLdapTest를 사용하여 LDAP 어플리케이션을 테스트할 수 있다.

- 일반적인 Component Bean들은 불러오지 않는다.

- 기본적으로 in-memory 내장형 LDAP과 Spring Data LDAP repository들과 LdapTemplate를 설정하며, @Entity 클래스들을 스캔한다.

- 만약 실제 LDAP 서버로 테스트하고 싶다면, 테스트 클래스에 @DataLdapTest(excludeAutoConfiguration = EmbeddedLdapAutoConfiguration.class)를 적용하면 된다.

 

(18) Auto-configured REST Clients

https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-client

- @RestClientTest를 사용하여 REST client들을 테스트할 수 있다. value 혹은 components 속성 인자를 사용하여 테스트하고자 하는 특정 bean들을 명시할 수 있다.

- 기본적으로 Jackson, GSON, Jsonb을 자동 설정해주고, RestTemplateBuilder을 설정한다. 

- 추가적으로 MockRestServiceServer라는 모의 서버 클래스도 지원한다.

- RestTemplateBuilder의 build()로 생성된 객체를 RestTemplate 객체에 주입함으로써 모든 URI 요청을 MockRestServiceServer 서버로 보낼 수 있다.

 

(19) Auto-configured REST Docs Tests

https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-docs

- Spring REST Docs는 RESTful 서비스의 문서화를 도와주는 도구이다.

- @AutoConfigureRestDocs를 사용하여 test상에서 Mock MVC, REST Assured, WebTestClient 중 하나를 사용한 Spring REST Docs를 사용할 수 있고, 기본 출력 디렉토리의 내부에 생성(출력)할 Docs 디렉토리를 지정 할 수 있다.

※ 기본 출력 디렉토리 : target/generated-snippets(Maven), build/generated-snippets(Gradle)

- Spring REST Docs에서는 JUnit 규칙이 필요하지 않게 된다.

- 문서화된 URI들에서 나타나는 host, scheme, port를 설정할 수 있다.

- RestDocumentationResultHandler @Bean을 생성해서, 각 Test들에 대한 Docs 생성 디렉토리명을 각 테스트 메소드의 이름으로 자동 적용시킬 수 있다.

 

(20) Additional Auto-configuration and Slicing

- 추가적인 자동 설정을 @ImportAutoConfiguration을 통해 추가할 수 있다. 인자에 자동 설정 클래스를 넣으면 된다.

 

(21) User Configuration and Slicing

- 특정 영역에 대한 설정 파일들은 따로 @Configuration 클래스로 분리를 하는 것이 권장된다.

- 추가적인 package들을 스캔할 경우에는 @ComponentScan을 이용할 수 있지만, 모든 slice들이 읽히게 된다.

 

(22) Using Spock to Test Spring Boot Applications

- Spock은 테스트를 보기 좋게 작성할 수 있는 방식이다.

 

 

4) Test Utilities

https://docs.spring.io/spring-boot/docs/2.1.13.RELEASE/reference/html/boot-features-testing.html#boot-features-test-utilities

(1) ConfigFileApplicationContextInitializer

- application.properties 파일을 테스트에 적용할 수 있는 ApplicationContextInitializer이다.

- @SpringBootTest에서 제공되는 기능들이 모두 필요한 것은 아닐 때 사용된다.

- 기본적으로 @Value는 제공되지 않지만, @Value를 사용하고 싶다면 PropertySourcesPlaceholderConfigurer를 설정하거나 @SpringBootTest를 사용한다.

 

(2) TestPropertyValues

- 프로퍼티들을 ConfigurableEnvironment 혹은 ConfigurableApplicationContext에 빠르게 추가할 때 사용된다.

TestPropertyValues.of("org=Spring", "name=Boot").applyTo(env);

 

(3) OutputCapture

- System.out과 System.err 출력을 확인할 수 있는 JUnit의 규칙이다.

- 이 방법보다 Logger를 쓰는 것이 낫다.

 

(4) TestRestTemplate

- RestTemplate을 테스트용으로 만든 것

- Redirect는 허용되지 않으므로 응답 위치를 assert할 수 있다.

- 쿠키가 무시된다.

- 대안으로, @SpringBootTest를 webEnvironment 속성값으로 WebEnvironment.RANDOM_PORT 혹은 WebEnvironment.DEFINED_PORT를 붙여 사용하게 되면 @Autowired로 완전한 TestRestTemplate 객체를 주입 받을 수 있다.

- RestTemplateBuilder bean을 통해 추가적인 커스터마이징을 적용할 수 있다.

- host와 port를 지정하지 않은 모든 URL은 자동으로 내장 서버로 전달된다.

 

 

-----------------------------------------------------------------------------------------------------

2022-01-02 내용 추가)

- assertThat([List]).contains([Element]) 메소드는 특정 요소가 List에 포함되어 있는가의 여부를 테스트할 수 있으며, contains에 객체가 들어갈 경우에는 객체 클래스 내부에 equals(), hashCode() 메소드를 오버라이딩할 것을 권장한다.

반응형

댓글