1. 개요
이 튜토리얼에서는 Spring Boot의 프레임 워크 지원을 사용하여 테스트를 작성 하는 방법을 살펴 봅니다 . 테스트를 실행하기 전에 Spring 컨텍스트를 부트 스트랩하는 통합 테스트뿐만 아니라 격리 된 상태에서 실행할 수있는 단위 테스트를 다룰 것입니다.
Spring Boot를 처음 사용하는 경우 Spring Boot 소개를 확인하십시오 .
2. 프로젝트 설정
이 기사에서 사용할 애플리케이션은 직원 리소스 에 대한 몇 가지 기본 작업을 제공하는 API입니다 . 이는 일반적인 계층 형 아키텍처입니다. API 호출은 컨트롤러 에서 서비스 , 지속성 계층으로 처리됩니다.
3. Maven 의존성
먼저 테스트 의존성을 추가해 보겠습니다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<version>2.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
스프링 부팅 선발 시험은 우리의 테스트에 필요한 요소의 대부분을 포함하는 주요 종속이다.
H2 DB는 우리의 인 메모리 데이터베이스입니다. 테스트 목적으로 실제 데이터베이스를 구성하고 시작할 필요가 없습니다.
3.1 JUnit 4
Spring Boot 2.4부터 JUnit 5의 빈티지 엔진이 spring-boot-starter-test 에서 제거되었습니다 . 여전히 JUnit 4를 사용하여 테스트를 작성하려면 다음 Maven 의존성을 추가해야합니다.
<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>
4. @SpringBootTest를 사용한 통합 테스트
이름에서 알 수 있듯이 통합 테스트는 애플리케이션의 여러 계층을 통합하는 데 중점을 둡니다. 그것은 또한 조롱이 포함되지 않음을 의미합니다.
이상적으로는 통합 테스트를 단위 테스트와 분리하여 유지해야하며 단위 테스트와 함께 실행해서는 안됩니다. 통합 테스트 만 실행하기 위해 다른 프로필을 사용하여이를 수행 할 수 있습니다. 이를 수행하는 몇 가지 이유는 통합 테스트에 시간이 많이 걸리고 실행하는 데 실제 데이터베이스가 필요할 수 있기 때문입니다.
그러나이 기사에서는 그것에 초점을 맞추지 않고 대신 메모리 내 H2 지속성 저장소를 사용할 것입니다.
통합 테스트는 테스트 케이스를 실행하기 위해 컨테이너를 시작해야합니다. 따라서이를 위해 몇 가지 추가 설정이 필요합니다.이 모든 것은 Spring Boot에서 쉽습니다.
@RunWith(SpringRunner.class)
@SpringBootTest(
SpringBootTest.WebEnvironment.MOCK,
classes = Application.class)
@AutoConfigureMockMvc
@TestPropertySource(
locations = "classpath:application-integrationtest.properties")
public class EmployeeRestControllerIntegrationTest {
@Autowired
private MockMvc mvc;
@Autowired
private EmployeeRepository repository;
// write test cases here
}
@SpringBootTest 우리는 전체 컨테이너 부트 스트랩해야 할 때 어노테이션에 유용합니다. 어노테이션은 테스트에서 활용 될 ApplicationContext 를 생성함으로써 작동 합니다.
우리는 사용할 수 webEnvironment의 의 속성 @SpringBootTest을 우리의 런타임 환경을 구성; 컨테이너가 모의 서블릿 환경에서 작동하도록 여기에서 WebEnvironment.MOCK을 사용 하고 있습니다.
다음으로 @TestPropertySource 어노테이션은 테스트에 특정한 속성 파일의 위치를 구성하는 데 도움이됩니다. @TestPropertySource로 로드 된 속성 파일 은 기존 application.properties 파일을 재정의 합니다.
application-integrationtest.properties는 지속성 스토리지를 구성하는 세부 사항을 포함 :
spring.datasource.url = jdbc:h2:mem:test
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect
MySQL에 대한 통합 테스트를 실행하려면 속성 파일에서 위의 값을 변경할 수 있습니다.
통합 테스트의 테스트 케이스는 컨트롤러 계층 단위 테스트 와 유사 할 수 있습니다 .
@Test
public void givenEmployees_whenGetEmployees_thenStatus200()
throws Exception {
createTestEmployee("bob");
mvc.perform(get("/api/employees")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content()
.contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$[0].name", is("bob")));
}
컨트롤러 계층 단위 테스트 와의 차이점은 여기서는 모의 대상이 없으며 종단 간 시나리오가 실행된다는 것입니다.
5. @TestConfiguration으로 구성 테스트
이전 섹션에서 보았 듯이 @SpringBootTest 어노테이션이 달린 테스트 는 전체 애플리케이션 컨텍스트를 부트 스트랩합니다. 즉, 구성 요소 스캔에서 선택한 모든 빈을 테스트로 @Autowire 할 수 있습니다 .
@RunWith(SpringRunner.class)
@SpringBootTest
public class EmployeeServiceImplIntegrationTest {
@Autowired
private EmployeeService employeeService;
// class code ...
}
그러나 실제 애플리케이션 컨텍스트를 부트 스트랩하는 것을 피하고 특별한 테스트 구성을 사용하고 싶을 수 있습니다. @TestConfiguration 어노테이션으로 이를 달성 할 수 있습니다 . 어노테이션을 사용하는 방법에는 두 가지가 있습니다. 빈 을 @Autowire 하려는 동일한 테스트 클래스의 정적 내부 클래스 중 하나입니다 .
@RunWith(SpringRunner.class)
public class EmployeeServiceImplIntegrationTest {
@TestConfiguration
static class EmployeeServiceImplTestContextConfiguration {
@Bean
public EmployeeService employeeService() {
return new EmployeeService() {
// implement methods
};
}
}
@Autowired
private EmployeeService employeeService;
}
또는 별도의 테스트 구성 클래스를 만들 수 있습니다.
@TestConfiguration
public class EmployeeServiceImplTestContextConfiguration {
@Bean
public EmployeeService employeeService() {
return new EmployeeService() {
// implement methods
};
}
}
@TestConfiguration 어노테이션이 달린 구성 클래스 는 구성 요소 스캔에서 제외되므로 @Autowire를 원하는 모든 테스트에서 명시 적으로 가져와야 합니다. @Import 어노테이션 을 사용하여이를 수행 할 수 있습니다 .
@RunWith(SpringRunner.class)
@Import(EmployeeServiceImplTestContextConfiguration.class)
public class EmployeeServiceImplIntegrationTest {
@Autowired
private EmployeeService employeeService;
// remaining class code
}
6. @MockBean으로 Mocking 하는방법
우리의 서비스 계층 코드는 우리에 의존 저장소 :
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
private EmployeeRepository employeeRepository;
@Override
public Employee getEmployeeByName(String name) {
return employeeRepository.findByName(name);
}
}
그러나 서비스 계층 을 테스트하기 위해 지속성 계층이 구현되는 방식을 알거나 신경 쓸 필요가 없습니다. 이상적으로는 전체 지속성 계층에 연결하지 않고도 서비스 계층 코드 를 작성하고 테스트 할 수 있어야합니다 .
이를 위해 Spring Boot Test에서 제공하는 모의 지원을 사용할 수 있습니다.
먼저 테스트 클래스 스켈레톤을 살펴 보겠습니다.
@RunWith(SpringRunner.class)
public class EmployeeServiceImplIntegrationTest {
@TestConfiguration
static class EmployeeServiceImplTestContextConfiguration {
@Bean
public EmployeeService employeeService() {
return new EmployeeServiceImpl();
}
}
@Autowired
private EmployeeService employeeService;
@MockBean
private EmployeeRepository employeeRepository;
// write test cases here
}
Service 클래스 를 확인하려면 테스트 클래스에서 @Autowire 할 수 있도록 @Bean 으로 생성되고 사용 가능한 Service 클래스 의 인스턴스가 있어야합니다 . @TestConfiguration 어노테이션을 사용하여이 구성을 수행 할 수 있습니다 .
여기서 또 다른 흥미로운 점은 @MockBean 의 사용입니다 . 이 모의을 생성 위한 EmployeeRepository 실제 호출 우회하는데 사용될 수 EmployeeRepository :
@Before
public void setUp() {
Employee alex = new Employee("alex");
Mockito.when(employeeRepository.findByName(alex.getName()))
.thenReturn(alex);
}
설정이 완료되었으므로 테스트 케이스가 더 간단 해집니다.
@Test
public void whenValidName_thenEmployeeShouldBeFound() {
String name = "alex";
Employee found = employeeService.getEmployeeByName(name);
assertThat(found.getName())
.isEqualTo(name);
}
7. @DataJpaTest를 사용한 통합 테스트
ID 와 이름 을 속성으로 갖는 Employee 라는 엔티티로 작업 할 것입니다 .
@Entity
@Table(name = "person")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Size(min = 3, max = 20)
private String name;
// standard getters and setters, constructors
}
다음은 SpringData JPA를 사용하는 저장소입니다.
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
public Employee findByName(String name);
}
이것이 지속성 레이어 코드입니다. 이제 테스트 클래스를 작성해 보겠습니다.
먼저 테스트 클래스의 골격을 만들어 보겠습니다.
@RunWith(SpringRunner.class)
@DataJpaTest
public class EmployeeRepositoryIntegrationTest {
@Autowired
private TestEntityManager entityManager;
@Autowired
private EmployeeRepository employeeRepository;
// write test cases here
}
@RunWith (SpringRunner.class) 는 Spring Boot 테스트 기능과 JUnit을 연결합니다. JUnit 테스트에서 Spring Boot 테스트 기능을 사용할 때마다이 어노테이션이 필요합니다.
@DataJpaTest 는 지속성 계층을 테스트하는 데 필요한 몇 가지 표준 설정을 제공합니다.
- 메모리 내 데이터베이스 인 H2 구성
- Hibernate, Spring Data 및 DataSource 설정
- @EntityScan 수행
- SQL 로깅 켜기
DB 작업을 수행하려면 데이터베이스에 이미 일부 레코드가 필요합니다. 이 데이터를 설정하기 위해 TestEntityManager 를 사용할 수 있습니다 .
Spring Boot TestEntityManager 는 테스트를 작성할 때 일반적으로 사용되는 메소드를 제공 하는 표준 JPA EntityManager 의 대안 입니다.
EmployeeRepository 는 테스트 할 구성 요소입니다.
이제 첫 번째 테스트 케이스를 작성해 보겠습니다.
@Test
public void whenFindByName_thenReturnEmployee() {
// given
Employee alex = new Employee("alex");
entityManager.persist(alex);
entityManager.flush();
// when
Employee found = employeeRepository.findByName(alex.getName());
// then
assertThat(found.getName())
.isEqualTo(alex.getName());
}
위의 테스트에서는 TestEntityManager 를 사용하여 직원 을 DB 에 삽입하고 이름으로 찾기 API를 통해 읽습니다.
assertThat (...) 부분은에서 온다 Assertj 라이브러리 Spring 부팅과 함께 번들로 제공됩니다.
8. @WebMvcTest를 사용한 단위 테스트
우리의 컨트롤러 에 따라 서비스 층; 단순성을 위해 단일 메서드 만 포함하겠습니다.
@RestController
@RequestMapping("/api")
public class EmployeeRestController {
@Autowired
private EmployeeService employeeService;
@GetMapping("/employees")
public List<Employee> getAllEmployees() {
return employeeService.getAllEmployees();
}
}
컨트롤러 코드 에만 집중하기 때문에 단위 테스트를 위해 서비스 레이어 코드 를 모의하는 것이 당연합니다 .
@RunWith(SpringRunner.class)
@WebMvcTest(EmployeeRestController.class)
public class EmployeeRestControllerIntegrationTest {
@Autowired
private MockMvc mvc;
@MockBean
private EmployeeService service;
// write test cases here
}
컨트롤러 를 테스트하기 위해 @WebMvcTest 를 사용할 수 있습니다 . 단위 테스트를 위해 Spring MVC 인프라를 자동 구성합니다.
대부분의 경우 @ WebMvcTest 는 단일 컨트롤러를 부트 스트랩하도록 제한됩니다. 필요한 의존성에 대한 모의 구현을 제공하기 위해 @MockBean 과 함께 사용할 수도 있습니다 .
@WebMvcTest 또한 자동 구성합니다 MockMvc 전체 HTTP 서버를 시작하지 않고 쉽게 테스트 MVC 컨트롤러의 강력한 방법을 제공합니다.
그런 다음 테스트 케이스를 작성해 보겠습니다.
@Test
public void givenEmployees_whenGetEmployees_thenReturnJsonArray()
throws Exception {
Employee alex = new Employee("alex");
List<Employee> allEmployees = Arrays.asList(alex);
given(service.getAllEmployees()).willReturn(allEmployees);
mvc.perform(get("/api/employees")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].name", is(alex.getName())));
}
GET (...) 메소드 호출은 같은 HTTP 동사에 해당하는 다른 방법으로 대체 될 수 넣어 () , 후 () 등, 우리는 또한 요청의 내용 유형을 설정하는 것을 바랍니다 메모를.
MockMvc 는 유연하며이를 사용하여 모든 요청을 생성 할 수 있습니다.
9. 자동 구성 테스트
Spring Boot의 자동 구성 어노테이션의 놀라운 기능 중 하나는 전체 애플리케이션의 일부를로드하고 코드베이스의 테스트 별 레이어를로드하는 데 도움이된다는 것입니다.
위에서 언급 한 어노테이션 외에도 널리 사용되는 어노테이션 List은 다음과 같습니다.
- @WebF luxTest : @WebFluxTest 어노테이션을 사용하여 Spring WebFlux 컨트롤러를 테스트 할 수 있습니다 . 필요한 의존성에 대한 모의 구현을 제공하기 위해 @MockBean 과 함께 자주 사용됩니다 .
- @JdbcTest : W e는 @JdbcTest 어노테이션을 사용하여 JPA 애플리케이션을 테스트 할 수 있지만 DataSource 만 필요한 테스트 용입니다 . 어노테이션은 인 메모리 임베디드 데이터베이스와 JdbcTemplate을 구성합니다.
- @JooqTest : jOOQ 관련 테스트를 테스트하기 위해 DSLContext 를 구성하는 @JooqTest 어노테이션을 사용할 수 있습니다 .
- @DataMongoTest : MongoDB 애플리케이션을 테스트하기 위해 @DataMongoTest 는 유용한 어노테이션입니다. 기본적으로 의존성을 통해 드라이버를 사용할 수있는 경우 메모리에 내장 된 MongoDB를 구성하고, MongoTemplate을 구성하고 , @Document 클래스를 스캔하고, SpringData MongoDB 저장소를 구성합니다.
- @DataRedisTest를 사용하면 Redis 애플리케이션을보다 쉽게 테스트 할 수 있습니다. @RedisHash 클래스를 스캔하고 기본적으로 SpringData Redis 저장소를 구성합니다.
- @DataLdapTest 는 인 메모리 임베디드 LDAP (사용 가능한 경우)를 구성하고, LdapTemplate을 구성하고 , @Entry 클래스를 스캔하고 , 기본적으로 SpringData LDAP 저장소를 구성 합니다.
- @RestClientTest : 일반적으로 @RestClientTest 어노테이션을 사용하여 REST 클라이언트를 테스트합니다. Jackson, GSON 및 Jsonb 지원과 같은 다양한 의존성을 자동 구성합니다. RestTemplateBuilder를 구성합니다 . 기본적으로 MockRestServiceServer 에 대한 지원을 추가합니다 .
- @JsonTest : JSON 직렬화를 테스트하는 데 필요한 Bean으로 만 Spring 애플리케이션 컨텍스트를 초기화합니다.
이러한 어노테이션과 통합 테스트를 최적화하는 방법에 대한 자세한 내용은 Spring Integration Tests 최적화 문서에서 확인할 수 있습니다 .
10. 결론
이 기사에서는 Spring Boot의 테스트 지원에 대해 자세히 알아보고 단위 테스트를 효율적으로 작성하는 방법을 보여주었습니다.
이 기사의 전체 소스 코드는 GitHub에서 찾을 수 있습니다 . 소스 코드에는 더 많은 예제와 다양한 테스트 케이스가 포함되어 있습니다.
테스트에 대해 계속 배우고 싶다면 통합 테스트 , Spring 통합 테스트 최적화 및 JUnit 5의 단위 테스트 와 관련된 별도의 기사가 있습니다 .
- https://docs.spring.io/spring-framework/docs/current/reference/html
- https://www.baeldung.com/spring-boot-testing
'Java' 카테고리의 다른 글
Spring Cloud Netflix 및 Feign과의 통합 테스트 (0) | 2021.03.08 |
---|---|
Spring WebClient 호출 로깅 (0) | 2021.03.08 |
Java 8 forEach 사용방법 (0) | 2021.03.08 |
JPA의 다 대다 관계 (0) | 2021.03.08 |
스프링 JDBC (0) | 2021.03.07 |