-
Notifications
You must be signed in to change notification settings - Fork 2
Cannot start new transaction without ending existing transaction #74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Could you please provide a minimal sample project for reproducing this issue. It's obvois that previous transaction wasn't closed properly, and so (most likely) some spring junit extension wasn't called at the right time (or at the expected sequence, or its a junit-store related issue). Only debugging on a real project could help in this case (to compare junit and spock behaviours). |
I used this sample project: https://github.com/mkyong/spring-boot/tree/master/spring-data-jpa Modified pom: <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-data-jpa</artifactId>
<packaging>jar</packaging>
<name>Spring Boot Spring Data JPA</name>
<url>https://mkyong.com</url>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.2</version>
</parent>
<properties>
<java.version>17</java.version>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</properties>
<dependencies>
<!-- Spring Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- in-memory database -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- ADDED -->
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>2.3-groovy-4.0</version>
<scope>test</scope>
</dependency>
<!-- ADDED -->
<dependency>
<groupId>ru.vyarus</groupId>
<artifactId>spock-junit5</artifactId>
<version>1.2.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<!-- ADDED -->
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<goals>
<goal>compileTests</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project> (added gmavenplus plugin and spock and spock-junit5 dependencies; note that I did not used spock-spring!) Next I rewritten BaseRepositoryTest into spock specification: package com.mkyong
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager
import spock.lang.Specification
import java.time.LocalDate
import static org.junit.jupiter.api.Assertions.assertEquals
@DataJpaTest
class BootTest extends Specification {
// Alternative for EntityManager
// Optional in this case, we can use bookRepository to do the same stuff
@Autowired
private TestEntityManager testEM;
@Autowired
private BookRepository bookRepository;
void setup() {
bookRepository.deleteAll();
bookRepository.flush();
testEM.clear();
}
def "Test save"() {
when:
Book b1 = new Book("Book A", BigDecimal.valueOf(9.99), LocalDate.of(2023, 8, 31));
//testEM.persistAndFlush(b1); the same
bookRepository.save(b1);
Long savedBookID = b1.getId();
Book book = bookRepository.findById(savedBookID).orElseThrow();
// Book book = testEM.find(Book.class, savedBookID);
then:
savedBookID == book.getId()
"Book A" == book.getTitle()
BigDecimal.valueOf(9.99) == book.getPrice()
LocalDate.of(2023, 8, 31) == book.getPublishDate()
}
def "Test update"() {
when:
Book b1 = new Book("Book A", BigDecimal.valueOf(9.99), LocalDate.of(2023, 8, 31));
//testEM.persistAndFlush(b1);
bookRepository.save(b1);
// update price from 9.99 to 19.99
b1.setPrice(BigDecimal.valueOf(19.99));
bookRepository.save(b1);
List<Book> result = bookRepository.findByTitle("Book A");
then:
1 == result.size()
Book book = result.get(0);
book.getId() != null
book.getId() > 0
assertEquals("Book A", book.getTitle());
assertEquals(BigDecimal.valueOf(19.99), book.getPrice());
assertEquals(LocalDate.of(2023, 8, 31), book.getPublishDate());
}
} (used only first 2 test methods) And it works. Did I miss anything? |
I'm running into the same issue after upgrading to spring 6. Trying to isolate exactly what is going on, but it seems to only trigger after running many tests, and specifically after a timeout when using |
According to SpringExtension source:
All required jupiter extensions supported. Moreover, TransactionalTestExecutionListener (throwing exception above) relies on I also verified that The issue might be caused by spock lifecicle specifics, but I have no idea what it could be. I tried to experiment with If you can prepare such example reproducing this problem (or could share your project) I would investigate it. |
I finally think I figured this out, and you said it in the comment, but I was working on upgrading an old project and didn't realize it had |
You don't need spock-spring for dependency injection! When you use spock-junit5 spring's junit 5 extension would manage dependency injection in test! I tested this - it works. |
The extension does not seem to support transactions when using spring jpa
I am getting the following exception:
java.lang.IllegalStateException: Cannot start new transaction without ending existing transaction at org.springframework.util.Assert.state(Assert.java:76) at org.springframework.test.context.transaction.TransactionalTestExecutionListener.beforeTestMethod(TransactionalTestExecutionListener.java:204) at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:320) at org.springframework.test.context.junit.jupiter.SpringExtension.beforeEach(SpringExtension.java:240) at ru.vyarus.spock.jupiter.interceptor.JunitApiExecutor.lambda$beforeEach$4(JunitApiExecutor.java:75) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at ru.vyarus.spock.jupiter.interceptor.JunitApiExecutor.beforeEach(JunitApiExecutor.java:75) at ru.vyarus.spock.jupiter.interceptor.ExtensionLifecycleMerger.interceptSetupMethod(ExtensionLifecycleMerger.java:127) at org.spockframework.runtime.extension.AbstractMethodInterceptor.intercept(AbstractMethodInterceptor.java:30) at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:101) at org.spockframework.spring.SpringInterceptor.interceptSetupMethod(SpringInterceptor.java:55) at org.spockframework.runtime.extension.AbstractMethodInterceptor.intercept(AbstractMethodInterceptor.java:30) at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:101) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:148) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.spockframework.runtime.model.MethodInfo.invoke(MethodInfo.java:156) at org.spockframework.runtime.model.MethodInfo.invoke(MethodInfo.java:156) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.spockframework.runtime.model.MethodInfo.invoke(MethodInfo.java:156) at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:102) at ru.vyarus.spock.jupiter.JunitExtensionSupport.lambda$visitSpec$1(JunitExtensionSupport.java:112) at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:101) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86) at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86) at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:119) at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:94) at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:89) at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:62) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33) at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94) at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193) at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129) at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100) at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60) at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56) at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113) at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65) at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69) at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
The text was updated successfully, but these errors were encountered: