[번역] 스프링 부트에서 테스트

in spring-boot •  3 years ago 

https://www.baeldung.com/spring-boot-testing/를 번역함.

1. 개요

이 튜토리얼에서는 Spring Boot의 프레임워크 지원을 사용하여 테스트를 작성 하는 방법을 살펴보겠습니다 테스트를 실행하기 전에 Spring 컨텍스트를 부트스트랩하는 통합 테스트뿐만 아니라 격리되어 실행할 수 있는 단위 테스트를 다룰 것입니다.

Spring Boot를 처음 사용하는 경우 Spring Boot에 대한 소개를 확인하십시오 .

2. 프로젝트 설정

이 기사에서 사용할 애플리케이션은 Employee Resource 에 대한 몇 가지 기본 작업을 제공하는 API입니다 . 이것은 전형적인 계층 구조입니다. API 호출은 컨트롤러 에서 서비스 , 지속성 계층으로 처리됩니다.

3. 메이븐 종속성

먼저 테스트 종속성을 추가해 보겠습니다.

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<version>2.5.0</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으로 조롱하기

우리의 서비스 계층 코드는 우리에 의존 저장소 :

@Service
public class EmployeeServiceImpl implements EmployeeService {

@Autowired
private EmployeeRepository employeeRepository;

@Override
public Employee getEmployeeByName(String name) {
return employeeRepository.findByName(name);
}
}

그러나 서비스 계층 을 테스트하기 위해 지속성 계층이 구현되는 방식을 알거나 신경 쓸 필요가 없습니다. 이상적으로는 전체 지속성 계층에서 연결하지 않고도 서비스 계층 코드 를 작성하고 테스트할 수 있어야 합니다 .

이를 위해 Spring Boot Test에서 제공하는 mocking 지원을 사용할 수 있습니다.

먼저 테스트 클래스 스켈레톤을 살펴보겠습니다.

@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
}

서비스 클래스 를 확인하려면 테스트 클래스에서 @Autowire 할 수 있도록 서비스 클래스 의 인스턴스를 생성하고 @Bean으로 사용할 수 있어야 합니다 . @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
}

다음은 Spring Data 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 구성
  • 최대 절전 모드, Spring 데이터 및 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에 Employee 를 삽입하고 이름으로 찾기 API를 통해 이를 읽습니다.

assertThat (...) 부분은에서 온다 Assertj 라이브러리 봄 부팅과 함께 번들로 제공됩니다.

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의 자동 구성 주석의 놀라운 기능 중 하나는 코드베이스의 전체 애플리케이션 및 테스트별 계층의 일부를 로드하는 데 도움이 된다는 것입니다.

위에서 언급한 주석 외에도 다음은 널리 사용되는 몇 가지 주석 목록입니다.

  • @WebF luxTest : @WebFluxTest 주석을 사용하여 Spring WebFlux 컨트롤러를 테스트 할 수 있습니다  .  필요한 종속성에 대한 모의 구현을 제공하기 위해 @MockBean 과 함께 자주 사용됩니다 .
  • @JdbcTest : W 전자는 사용할 수 @JdbcTest 테스트 JPA 애플리케이션에 주석을하지만, 그것은 단지 필요 시험의 데이터 소스를. 주석은 메모리 내장 데이터베이스와 JdbcTemplate을 구성합니다.
  • @JooqTest : jOOQ 관련 테스트를 테스트하기 위해 DSLContext 를 구성하는 @JooqTest 주석을 사용할 수 있습니다  .
  • @DataMongoTest : MongoDB 애플리케이션을 테스트하기 위해 @DataMongoTest 는 유용한 주석입니다. 기본적으로 종속성을 통해 드라이버를 사용할 수 있는 경우 인메모리 임베디드 MongoDB를 구성하고, MongoTemplate을 구성하고 @Document 클래스를 검색하고 , Spring Data MongoDB 리포지토리를 구성합니다.
  • @DataRedisTest 사용하면 Redis 애플리케이션을 더 쉽게 테스트할 수 있습니다. @RedisHash 클래스를 검색 하고 기본적으로 Spring Data Redis 저장소를 구성합니다.
  • @DataLdapTest  는 메모리 내장 LDAP (사용 가능한 경우)를 구성하고, LdapTemplate을 구성하고 , @Entry 클래스를 검색하고 , 기본적으로 Spring Data LDAP 저장소를 구성 합니다.
  • @RestClientTest : 일반적으로 @RestClientTest 주석을 사용하여 REST 클라이언트를 테스트합니다. Jackson, GSON 및 Jsonb 지원과 같은 다양한 종속성을 자동 구성합니다. RestTemplateBuilder를 구성합니다 기본적으로 MockRestServiceServer 에  대한 지원을 추가합니다 .
  • @JsonTest : JSON 직렬화 테스트에 필요한 Bean으로만 Spring 애플리케이션 컨텍스트를 초기화합니다.

이러한 주석과 통합 테스트를 추가로 최적화하는 방법에 대한 자세한 내용은 Spring 통합 테스트 최적화 기사에서 읽을 수 있습니다 .

10. 결론

이 기사에서는 Spring Boot의 테스트 지원에 대해 자세히 살펴보고 단위 테스트를 효율적으로 작성하는 방법을 보여주었습니다.

이 기사의 전체 소스 코드는 GitHub에서 찾을 수 있습니다 . 소스 코드에는 더 많은 예제와 다양한 테스트 사례가 포함되어 있습니다.

당신이 시험에 대한 학습 유지하려는 경우, 우리는 별도의 관련 기사가 통합 테스트 , 스프링 통합 테스트를 최적화 하고, JUnit을 5 단위 테스트를 .



Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!