Я пишу интеграционный тест для SpringBoot 2 RestController. Я хочу протестировать поведение 404 и создание сущностей. Однако, когда я пытаюсь создать сущности и сохранять их до или во время теста, они не сохраняются в контексте SpringBoot. Под этим я подразумеваю, что они видны в контексте теста (во время отладки теста), но не для Контроллера (т.е. он их не находит, и мои тесты терпят неудачу). Что я делаю неправильно?
Как я могу сохранять сущности и очищать контекст во время теста, чтобы код, вызываемый во время интеграционного теста, их видел? Я не хочу использовать аннотацию @before для заполнения базы данных, потому что я хочу сделать это в своих методах @test.
Вот мой код. Спасибо
@RunWith(SpringRunner.class)
@Transactional
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class InvoiceControlllerIT extends GenericControllerIT {
@Autowired
EntityManager entityManager;
@Test
@Transactional
public void cascadesChildEntityAssociationOnCreate() throws IOException {
assertThat(invoicerRepository.count(), equalTo(0L));
assertThat(invoiceRepository.count(), equalTo(0L));
assertThat(invoiceeRepository.count(), equalTo(0L));
// create an invoicee
Invoicee savedInvoicee = invoiceeRepository.save(new Invoicee());
assertThat(invoiceeRepository.count(), equalTo(1L));
// create an invoicer
Invoicer savedInvoicer = invoicerRepository.save(new Invoicer());
assertThat(invoicerRepository.count(), equalTo(1L));
// THIS IS THE PROBLEM, FLUSHING DURING THE TEST DOES NOT EFFECT THE CONTROLLERS ABILITY TO SEE THE NEWLY CREATED ENTITIES
entityManager.flush();
// create input
InvoiceInputDto inputDto = InvoiceInputDto
.builder()
.invoicee(savedInvoicee.getId())
.invoicer(savedInvoicer.getId())
.name("test-name")
.build();
// make call
ResponseEntity<InvoiceDto> response = template.postForEntity(url("/invoices", TOKEN), inputDto, InvoiceDto.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.CREATED));
assertThat(response.getBody().getName(), equalTo(inputDto.getName()));
// check associations
assertThat(invoiceeRepository.findById(savedInvoicee.getId()).get().getInvoices(), hasSize(1));
}
}




Согласно документам:
If your test is @Transactional, it rolls back the transaction at the end of each test method by default. However, as using this arrangement with either RANDOM_PORT or DEFINED_PORT implicitly provides a real servlet environment, the HTTP client and server run in separate threads and, thus, in separate transactions. Any transaction initiated on the server does not roll back in this case
Поскольку тестовая транзакция отделена от транзакции HTTP-сервера, контроллер не увидит изменений, внесенных в тестовом методе, пока тестовая транзакция не будет фактически зафиксирована. И наоборот, вы не сможете откатить изменения, внесенные в результате вызова сервера.
Вы серьезно упростите себе жизнь, предоставив имитацию реализации для любого сервиса / репозитория, который использует ваш контроллер. В качестве альтернативы вы можете использовать такой инструмент, как DBUnit, для настройки и удаления базы данных для каждого тестового примера.
Спасибо, в итоге я изменил способ тестирования