I have a small problem. I have started writing tests for my small project. The project uses SpringBoot, standard JpaRepository from Spring, as a testing framework I am using Spock and for testing the database, I’m using PostgreSQL container from TestContainers. The problem is, that data between tests is being persisted, despite the @Transacional on each of the tests. The strangest part is, that in the logs I can see, that transaction is rolled back. I would appreciate any help.
So, these are the files:
- File with a shared container for tests, that all integration tests should extend from:
@SpringBootTest(classes = DatabaseMain.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @Testcontainers class BaseTestIT extends Specification { private static final Logger LOG = LoggerFactory.getLogger(BaseTestIT.class); @Shared private static final PostgreSQLContainer POSTGRES_CONTAINER = new PostgreSQLContainer("postgres") .withDatabaseName('test').withUsername( 'test').withPassword('test'); ... }
- File with configuration:
@Configuration @PropertySource("database.properties") public class ConfigurationIT { private final String databaseUrl; private final String databaseDialect; private final String databaseType; @Autowired public ConfigurationIT(@Value("${test.database.url}") String databaseUrl, @Value("${test.database.dialect}") String databaseDialect, @Value("${test.database.type}") String databaseType) { this.databaseDialect = databaseDialect; this.databaseUrl = databaseUrl; this.databaseType = databaseType; } @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory() { LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class); entityManagerFactoryBean.setPersistenceUnitName("testIT"); entityManagerFactoryBean.setPackagesToScan("com.testproject"); Map<String, String> properties = new HashMap<>(); properties.put("spring.jpa.database", this.databaseType); properties.put("spring.jpa.database-platform", this.databaseDialect); properties.put("hibernate.dialect", this.databaseDialect); properties.put("hibernate.connection.url", this.databaseUrl); entityManagerFactoryBean.setJpaPropertyMap(properties); return entityManagerFactoryBean; } @Bean @Autowired public JpaTransactionManager transactionManager(LocalContainerEntityManagerFactoryBean emf) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(emf.getObject()); return transactionManager; } }
- application.yaml
spring: datasource: driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver url: ${test.database.url} username: ${test.database.username} password: ${test.database.password} jpa: database-platform: ${test.database.dialect} database: ${test.database.type}
- and test file:
@SpringBootTest(classes = DatabaseMain.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) @Testcontainers class ArchitectTestIT extends BaseTestIT { private static final String NAME = "name"; private static final String LAST_NAME = "last_name"; @Autowired private TestRestTemplate restTemplate; @Autowired private ArchitectRepository architectRepository; @Transactional(propagation = Propagation.REQUIRES_NEW) def "Creating Architect with proper DTO should return created architect and 201 code"() { given: "proper architect dto" ArchitectBasicDto architectBasicDto = new ArchitectBasicDto(); architectBasicDto.setFirstName(NAME); architectBasicDto.setLastName(LAST_NAME); HttpEntity entity = new HttpEntity(architectBasicDto); when: "passed to architect post method" def exchange = this.restTemplate.exchange("/architects", HttpMethod.POST, entity, ArchitectBasicDto.class); then: "returns code 201 with dto of created Architected with location in the header" exchange.statusCode == HttpStatus.CREATED; and: exchange.getBody().getFirstName() == NAME; and: exchange.getBody().getLastName() == LAST_NAME; and: def id = exchange.getBody().getId() id != null; and: exchange.getHeaders().get("Location").get(0) == "/architects/" + id; } @Transactional(propagation = Propagation.REQUIRES_NEW) def "Creating Architect with not proper DTO should return code 400 and not create new Architect"() { given: ArchitectBasicDto architectBasicDto = new ArchitectBasicDto(); architectBasicDto.setFirstName(null); architectBasicDto.setLastName(LAST_NAME); HttpEntity entity = new HttpEntity(architectBasicDto); when: def exchange = this.restTemplate.exchange("/architects", HttpMethod.POST, entity, ArchitectBasicDto.class); then: exchange.statusCode == HttpStatus.BAD_REQUEST; and: exchange.getBody().getId() == null; amd: exchange.getBody().getFirstName() == null; and: exchange.getBody().getLastName() == null; } @Transactional(propagation = Propagation.REQUIRES_NEW) def "Removing existing Architect will return code 200 and remove it from database"() { given: ArchitectBasicDto architectBasicDto5 = new ArchitectBasicDto(); architectBasicDto5.setFirstName(NAME); architectBasicDto5.setLastName(LAST_NAME); HttpEntity entity5 = new HttpEntity(architectBasicDto5); ResponseEntity<ArchitectBasicDto> exchange5 = this.restTemplate.exchange("/architects", HttpMethod.POST, entity5, ArchitectBasicDto.class); HttpEntity entity = new HttpEntity(null); when: ResponseEntity<ArchitectBasicDto> exchange = this.restTemplate.exchange("/architects/" + exchange5.getBody().getId(), HttpMethod.DELETE, entity, ArchitectBasicDto.class); then: exchange.statusCode == HttpStatus.OK; } @Transactional(propagation = Propagation.REQUIRES_NEW) def "Removing not existing Architect will give code 400 and error message about not existing Architect"() { given: HttpEntity entity = new HttpEntity(null); when: ResponseEntity<Map<String, String>> exchange = this.restTemplate.exchange("/architects/" + 2000, HttpMethod.DELETE, entity, Map<String, String>.class); then: exchange.statusCode == HttpStatus.BAD_REQUEST; and: exchange.getBody().get("message") == "Architect with id 2,000 does not exist."; } @Transactional(propagation = Propagation.REQUIRES_NEW) def "Calling get on /architects should return all architects basic dto"() { given: HttpEntity entity = new HttpEntity(null); when: ResponseEntity<List<ArchitectBasicDto>> exchange = this.restTemplate.exchange("/architects", HttpMethod.GET, entity, List<ArchitectBasicDto>.class); then: exchange.getBody().size() == 0; } }
The last test was a bit modified, just to show the problem. As I do not save any of the Entities, it should pass, while it does not:
Condition not satisfied: exchange.getBody().size() == 0 | | | | | | 1 false | [[id:100, firstName:name, lastName:last_name]] <200,[{id=100, firstName=name, lastName=last_name}],[Content-Type:"application/json", Transfer-Encoding:"chunked", Date:"Thu, 16 Dec 2021 20:55:38 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]>
And as for logs, they show that transactions are being rolled back:
[2021-12-16T21:55:38,337] INFO [main][] - TransactionContext.startTransaction(TransactionContext.java:107) - Began transaction (1) for test context [DefaultTestContext@4a8d8f50 testClass = ArchitectTestIT, testInstance = com.testproject.task.architect.application.ArchitectTestIT@5a30ab46, testMethod = $spock_feature_1_0@ArchitectTestIT, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@7772549d testClass = ArchitectTestIT, locations = '{}', classes = '{class com.testproject.task.DatabaseMain}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.spockframework.spring.mock.SpockContextCustomizer@0, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@628c4ac0, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@363042d7, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@447a020, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@56113384, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@41dd05a, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@39ba5a14], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> false, 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@4df4f611]; rollback [true] [2021-12-16T21:55:38,589] INFO [http-nio-8080-exec-1][] - DirectJDKLog.log(DirectJDKLog.java:173) - Initializing Spring DispatcherServlet 'dispatcherServlet' [2021-12-16T21:55:38,589] INFO [http-nio-8080-exec-1][] - FrameworkServlet.initServletBean(FrameworkServlet.java:525) - Initializing Servlet 'dispatcherServlet' [2021-12-16T21:55:38,591] INFO [http-nio-8080-exec-1][] - FrameworkServlet.initServletBean(FrameworkServlet.java:547) - Completed initialization in 2 ms [2021-12-16T21:55:38,745] INFO [main][] - TransactionContext.endTransaction(TransactionContext.java:139) - Rolled back transaction for test: [DefaultTestContext@4a8d8f50 testClass = ArchitectTestIT, testInstance = com.testproject.task.architect.application.ArchitectTestIT@5a30ab46, testMethod = $spock_feature_1_0@ArchitectTestIT, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@7772549d testClass = ArchitectTestIT, locations = '{}', classes = '{class com.testproject.task.DatabaseMain}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.spockframework.spring.mock.SpockContextCustomizer@0, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@628c4ac0, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@363042d7, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@447a020, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@56113384, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@41dd05a, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@39ba5a14], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> false, 'org.spockframework.spring.SpringMockTestExecutionListener.MOCKED_BEANS_LIST' -> list[[empty]], 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]] [2021-12-16T21:55:38,749] INFO [main][] - TransactionContext.startTransaction(TransactionContext.java:107) - Began transaction (1) for test context [DefaultTestContext@4a8d8f50 testClass = ArchitectTestIT, testInstance = com.testproject.task.architect.application.ArchitectTestIT@317e9cf5, testMethod = $spock_feature_1_1@ArchitectTestIT, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@7772549d testClass = ArchitectTestIT, locations = '{}', classes = '{class com.testproject.task.DatabaseMain}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.spockframework.spring.mock.SpockContextCustomizer@0, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@628c4ac0, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@363042d7, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@447a020, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@56113384, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@41dd05a, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@39ba5a14], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> false, 'org.spockframework.spring.SpringMockTestExecutionListener.MOCKED_BEANS_LIST' -> list[[empty]], 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@4df4f611]; rollback [true] [2021-12-16T21:55:38,759] ERROR [http-nio-8080-exec-2][] - GlobalExceptionHandler.handleException(GlobalExceptionHandler.java:33) - isNull.architect.firstName com.testproject.task.sharedkernel.exceptions.IllegalArgumentException: isNull.architect.firstName at com.testproject.task.sharedkernel.exceptions.BaseValidator.assertIsTrue(BaseValidator.java:36) ~[classes/:?] at com.testproject.task.architect.application.ArchitectValidator.validateName(ArchitectValidator.java:50) ~[classes/:?] at com.testproject.task.architect.application.ArchitectValidator.validateBasicArchitectDto(ArchitectValidator.java:38) ~[classes/:?] at com.testproject.task.architect.application.impl.ArchitectApplicationServiceImpl.createArchitect(ArchitectApplicationServiceImpl.java:41) ~[classes/:?] at com.testproject.task.architect.application.impl.ArchitectApplicationServiceImpl$$FastClassBySpringCGLIB$$e4b5b2ac.invoke(<generated>) ~[classes/:?] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.8.jar:5.3.8] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779) ~[spring-aop-5.3.8.jar:5.3.8] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.8.jar:5.3.8] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.3.8.jar:5.3.8] at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.8.jar:5.3.8] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.8.jar:5.3.8] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.8.jar:5.3.8] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.8.jar:5.3.8] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.3.8.jar:5.3.8] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692) ~[spring-aop-5.3.8.jar:5.3.8] at com.testproject.task.architect.application.impl.ArchitectApplicationServiceImpl$$EnhancerBySpringCGLIB$$e31df751.createArchitect(<generated>) ~[classes/:?] at com.testproject.task.architect.rest.ArchitectRestController.createArchitect(ArchitectRestController.java:36) ~[classes/:?] at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?] at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64) ~[?:?] at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?] ... at java.lang.Thread.run(Thread.java:832) [?:?] [2021-12-16T21:55:38,810] INFO [main][] - TransactionContext.endTransaction(TransactionContext.java:139) - Rolled back transaction for test: [DefaultTestContext@4a8d8f50 testClass = ArchitectTestIT, testInstance = com.testproject.task.architect.application.ArchitectTestIT@317e9cf5, testMethod = $spock_feature_1_1@ArchitectTestIT, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@7772549d testClass = ArchitectTestIT, locations = '{}', classes = '{class com.testproject.task.DatabaseMain}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.spockframework.spring.mock.SpockContextCustomizer@0, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@628c4ac0, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@363042d7, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@447a020, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@56113384, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@41dd05a, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@39ba5a14], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> false, 'org.spockframework.spring.SpringMockTestExecutionListener.MOCKED_BEANS_LIST' -> list[[empty]], 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]] [2021-12-16T21:55:38,818] INFO [main][] - TransactionContext.startTransaction(TransactionContext.java:107) - Began transaction (1) for test context [DefaultTestContext@4a8d8f50 testClass = ArchitectTestIT, testInstance = com.testproject.task.architect.application.ArchitectTestIT@9b8d3db, testMethod = $spock_feature_1_2@ArchitectTestIT, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@7772549d testClass = ArchitectTestIT, locations = '{}', classes = '{class com.testproject.task.DatabaseMain}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.spockframework.spring.mock.SpockContextCustomizer@0, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@628c4ac0, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@363042d7, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@447a020, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@56113384, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@41dd05a, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@39ba5a14], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> false, 'org.spockframework.spring.SpringMockTestExecutionListener.MOCKED_BEANS_LIST' -> list[[empty]], 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@4df4f611]; rollback [true] [2021-12-16T21:55:39,054] INFO [main][] - TransactionContext.endTransaction(TransactionContext.java:139) - Rolled back transaction for test: [DefaultTestContext@4a8d8f50 testClass = ArchitectTestIT, testInstance = com.testproject.task.architect.application.ArchitectTestIT@9b8d3db, testMethod = $spock_feature_1_2@ArchitectTestIT, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@7772549d testClass = ArchitectTestIT, locations = '{}', classes = '{class com.testproject.task.DatabaseMain}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.spockframework.spring.mock.SpockContextCustomizer@0, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@628c4ac0, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@363042d7, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@447a020, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@56113384, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@41dd05a, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@39ba5a14], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> false, 'org.spockframework.spring.SpringMockTestExecutionListener.MOCKED_BEANS_LIST' -> list[[empty]], 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]
So I’m a bit stuck, as for what could be the reason why those are not actually being rolled back and I would appreciate any help with that. Thanks!
Advertisement
Answer
Your tests start an app that listens on a real port. And you use TestRestTemplate to make HTTP calls. It’s the same as if you ran your test from a remote machine – would you expect @Transactional
on such tests to be some how applied to the app?
@Transactional
will work only if you invoke your endpoint directly, without any network calls:
- either inject endpoint object directly to your test and call its method
- or use MockMvc (or RestAssured+MockMvc) – it will also eventually call the endpoint directly
Both of these options will simplify debugging – you’ll be able to see in call stack which test is calling your production code at the moment.
PS: also it shouldn’t be a problem when your data is kept between test runs. You can isolate your tests with randomization.