unitarias tipos software pruebas integrales integración integracion estrés ejemplos ejemplo carga hibernate spring transactions integration-testing rollback

hibernate - tipos - pruebas unitarias angular 6



Cómo revertir transacciones anidadas con Propagation.REQUIRES_NEW en pruebas de integración (2)

Tengo varias pruebas de integración para varios servicios que extienden la siguiente clase de base:

@ContextConfiguration(locations="classpath:applicationContext-test.xml") @TransactionConfiguration(transactionManager="txManager", defaultRollback=true) @Transactional public abstract class IntegrationTestBase extends AbstractTransactionalJUnit4SpringContextTests { //Some setup, filling test data to a HSQLDB-database etc }

Para la mayoría de los casos, esto funciona bien, pero tengo una clase de servicio que tiene transacciones definidas con propagation=Propagation.REQUIRES_NEW . Parece que estas transacciones no se retrotraen (¿porque son transacciones anidadas y aparentemente se comprometen dentro de la transacción "externa"?). La transacción "externa" (nivel de caso de prueba) se retrotrae, al menos de acuerdo con los registros de prueba. Las transacciones comprometidas arruinan algunas pruebas posteriores, porque han cambiado los datos de prueba.

Puedo evitar esto forzando la prueba para volver a crear y rellenar la base de datos entre las pruebas, pero mi pregunta es: ¿es este comportamiento esperado o estoy haciendo algo mal en mis pruebas? ¿Se puede obligar a la transacción anidada a retroceder desde el código de prueba?


Agregué un comentario al jira.springsource.org/browse/SPR-6908 primavera sobre esto. Lo copiaré aquí también:

Resolví este problema convirtiendo todos los métodos de servicio que se configuraron declarativamente como este

@Transactional(propagation = REQUIRES_NEW) public Object doSmth() { // doSmthThatRequiresNewTx }

para utilizar TransactionTemplate lugar:

private TransactionTemplate transactionTemplate; public Object doSmth() { return transactionTemplate.execute(new TransactionCallback<Object>() { @Override public Object doInTransaction(TransactionStatus status) { // doSmthThatRequiresNewTx } }); }

Bajo las pruebas, configuro el comportamiento de propagación de transactionTemplate para que sea PROPAGATION_REQUIRED , bajo la aplicación real, configuro el comportamiento de propagación de transactionTemplate para que sea PROPAGATION_REQUIRES_NEW . Funciona como se esperaba. La limitación de esta solución es que, bajo las pruebas, no es posible afirmar el hecho de que la transacción interna no se revierte en un escenario excepcional.

La otra solución sería eliminar explícitamente todo lo que doSmth() en la base de datos en el método @AfterTransaction en prueba. Ese ''eliminar'' SQL se ejecutará en la nueva transacción, ya que de lo contrario, sus resultados se revertirán rutinariamente por el comportamiento predeterminado de Spring TransactionConfiguration .


Este es el comportamiento esperado, y es una de las razones principales para usar REQUIRES_NEW:

  • ser capaz de revertir la nueva transacción, pero cometer la externa
  • Poder cometer la nueva transacción, pero revertir la externa.

volver a llenar la base de datos entre las pruebas es probablemente la mejor solución, y usaría esta solución para todas las pruebas: esto permite que las pruebas comprueben que todo funciona correctamente, incluido el compromiso (que podría fallar debido a la descarga, las restricciones diferidas, etc.) ).

Pero si realmente desea revertir la transacción, una solución sería agregar un argumento booleano rollbackAtTheEnd a su servicio y revertir la transacción si este argumento es verdadero.