Реализовать Rest тест с базой данных - PullRequest
0 голосов
/ 12 декабря 2018
@RestController
@RequestMapping("/transactions")
public class PaymentTransactionsController {

    @Autowired
    private PaymentTransactionRepository transactionRepository;

    @GetMapping("{id}")
    public ResponseEntity<?> get(@PathVariable String id) {
        return transactionRepository
                .findById(Integer.parseInt(id))
                .map(mapper::toDTO)
                .map(ResponseEntity::ok)
                .orElseGet(() -> notFound().build());
    }

JUnit 5 test:

@ExtendWith({ RestDocumentationExtension.class, SpringExtension.class })
@SpringBootTest(classes = PaymentTransactionsController.class)
public class ApiDocumentationJUnit5IntegrationTest {

    @Autowired
    private ObjectMapper objectMapper;

    private MockMvc mockMvc;

    @BeforeEach
    public void setUp(WebApplicationContext webApplicationContext, RestDocumentationContextProvider restDocumentation) {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
                .apply(documentationConfiguration(restDocumentation)).build();
    }

    @Test
    public void uniqueTransactionIdLenght() {
        try {
            this.mockMvc.perform(RestDocumentationRequestBuilders.get("/transactions/1")).andExpect(status().isOk())
                    .andExpect(content().contentType("application/xml;charset=UTF-8"))
                    .andDo(document("persons/get-by-id"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

PaymentTransactionRepository - это интерфейс, который я использую для определения репозитория.Наверное мне нужно заглушить запрос и вернуть тестовые данные?Как правильно заглушить запрос?Я получаю

Field transactionRepository in org.restapi.PaymentTransactionsController required a bean of type 'org.backend.repo.PaymentTransactionRepository' that could not be found.

Ответы [ 2 ]

0 голосов
/ 14 декабря 2018

Интеграционный тест контроллера

О тестировании интеграции из контекста контроллера, если ваша цель - проведение интеграционного тестирования с использованием фактического источника данных, к которому добавлено: PaymentTransactionRepository.

Задача:

Для решения:

Field transactionRepository in org.restapi.PaymentTransactionsController required a bean of type 'org.backend.repo.PaymentTransactionRepository' that could not be found.

Или что-то эквивалентное, например:

java.lang.IllegalStateException: Failed to load ApplicationContext

Caused by: 

    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'paymentTransactionsController': Unsatisfied dependency expressed through field 'transactionRepository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.data.PaymentTransactionRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

Caused by: 

    org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.data.PaymentTransactionRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

Заменить:

@ExtendWith({ RestDocumentationExtension.class, SpringExtension.class })
@SpringBootTest(classes = PaymentTransactionsController.class)
public class ApiDocumentationJUnit5IntegrationTest {

По:

@RunWith(SpringRunner.class)
@SpringBootTest
public class ApiDocumentationJUnit5IntegrationTest {

С:

SpringBootTest: Автоматический поиск @SpringBootConfiguration, когда вложенная @Configuration не используется и явные классы не указаны.

См. Spring Docs

Тест интеграции DataJpaTest

Как вы недавно спрашивали, пример тестирования DataJpaTest, предполагающий, что метод findById класса PaymentTransactionRepository возвращает Optional<DTO>, будет выглядеть следующим образом:

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;
import java.util.Optional;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@SpringBootTest
public class PaymentTransactionRepositoryIntegrationTest {

    @Autowired
    PaymentTransactionRepository target;

    @BeforeEach
    public void setUp() throws Exception {
    }

    @Test
    public void testNotNull() {
        assertNotNull(target);
    }

    @Test
    public void testFindByIdFound() {
        Optional<DTO> res = target.findById(1L);
        assertTrue(res.isPresent());
    }

    @Test
    public void testFindByIdNotFound() {
        Optional<DTO> res = target.findById(3L);
        assertFalse(res.isPresent());
    }
}

Функциональный пример

Пожалуйста, найдите здесь простой пример, на 100% функциональный, который представляет собой предварительную загрузку тестовых данных с использованием базы данных H2 в памяти и содержит минимально необходимую конфигурацию грейфера / пружины для прохождения тестов.Он включает в себя 2 типа интеграционных тестов с использованием SprinbBoot2 (JPA) и JUnit5, 1) контроллер: ApiDocumentationJUnit5IntegrationTest и 2) репозиторий: PaymentTransactionRepositoryIntegrationTest.

0 голосов
/ 12 декабря 2018

Вы можете использовать @MockBean для создания заглушки хранилища в контексте приложения:

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = PaymentTransactionsController.class)
class ApiDocumentationJUnit5IntegrationTest {

  @MockBean
  private PaymentTransactionRepository transactionRepository;

  ...

  @BeforeEach
  void setUp() {
    when(transactionRepository.findById(eq(ID))).thenReturn(mock);
  }

  @Test
  void testSomething(){
     ...
  }

Также вы можете изменить область тестов на DataJpaTest или использовать весь контекст приложения изапустить тест с подготовленными данными в реальной базе данных.В этом случае вы можете тестировать не только логику контроллера, вы будете тестировать логику всей системы.

@DataJpaTest 
@ExtendWith(SpringExtension.class)
class ApiDocumentationJUnit5IntegrationTest {

  @Autowired
  private PaymentTransactionRepository transactionRepository;

  @Test
  void testSomething(){
     List<Payment> payments = transactionRepository.findAll();
     assertThat(payments).hasSize(3);
     ...
  }
}

Для запуска этого теста вам потребуется конфигурация базы данных для тестов.Если вы не используете нативные запросы в своем приложении, вы можете использовать h2.Но если вы интенсивно используете собственные запросы и что-то особенное для вашей целевой базы данных, вы можете использовать библиотеку TestContainers для запуска вашего реального образа базы данных в Docker и запуска тестов для этого образа.

...