question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

@Transactional ignored in any @Nested test class

See original GitHub issue

Describe the bug

According to the docs, @QuarkusTest classes support the use of @Transactional tests. ~This does not seem to be the case for test setup methods annotated with @BeforeEach, though.~ Edit: This does not seem to be the case for @Nested tests, though. (I have commented out irrelevant parts)

When running the following test, I get an exception telling me that user.delete() has been called outside of a transaction:

@QuarkusTest
public class MyTest {

	@Nested
	@FlywayTest(value = @DataSource(url = "jdbc:h2:mem:test"))
	public class NestedClass {

		@Test
		@Transactional
		public void test() {
			User user = User.findById("user1");
			user.delete();
		}

	}

	/* Edit: This was my original test case. turns out the aforementioned is sufficient
	@Nested
	@FlywayTest(value = @DataSource(url = "jdbc:h2:mem:test"), clean = false)
	@DisplayName("when removing a user")
	public class AfterRemovingUser {

		@BeforeEach
		@Transactional
		public void setup() {
			User user = User.findById("user1");
			user.delete();
		}

		@Test
		@Transactional
		@DisplayName("the user's devices get deleted")
		public void testCascadeToDevices() {
			boolean match = Device.<Device>findAll().stream().anyMatch(d -> "user1".equals(d.owner.id));
			Assertions.assertFalse(match);
		}

	}
	*/


	/* other tests */

}
javax.persistence.TransactionRequiredException: Transaction is not active, consider adding @Transactional to your method to automatically activate one.

	at io.quarkus.hibernate.orm.runtime.session.TransactionScopedSession.remove(TransactionScopedSession.java:160)
	at io.quarkus.hibernate.orm.runtime.session.ForwardingSession.remove(ForwardingSession.java:63)
	at org.hibernate.Session_5b93bee577ae2f8d76647de04cfab36afbf52958_Synthetic_ClientProxy.remove(Session_5b93bee577ae2f8d76647de04cfab36afbf52958_Synthetic_ClientProxy.zig:1276)
	at io.quarkus.hibernate.orm.panache.common.runtime.AbstractJpaOperations.delete(AbstractJpaOperations.java:122)
	at io.quarkus.hibernate.orm.panache.PanacheEntityBase.delete(PanacheEntityBase.java:80)
	at com.example.MyTest$AfterRemovingUser.setup(MyTest.java:50)

Expected behavior

Any method inside of a @QuarkusTest supports @Transactional in the same way.

Actual behavior

While @Transactional ~is supported on the @Test methods themselves, it seems to be ignored during test setup.~ is supported on the root level, it is ignored in @Nested tests.

How to Reproduce?

Create Panache entities for the following two tables and run the aforementioned test.

-- flyway ddl:
CREATE TABLE user
(
    id   VARCHAR(255) NOT NULL,
    name VARCHAR(255) NOT NULL,
    CONSTRAINT PK_USER PRIMARY KEY (id)
);

/*
-- CREATE TABLE device
(
    id        VARCHAR(255) NOT NULL,
    user_id   VARCHAR(255) NOT NULL,
    name      VARCHAR(255) NOT NULL,
    CONSTRAINT PK_DEVICE PRIMARY KEY (id),
    CONSTRAINT FK_DEVICE_ON_USER FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE
);
*/

-- flyway test data:
INSERT INTO user (id, name)
VALUES
    ('user1', 'User Name 1');

/*
INSERT INTO device (id, user_id, name)
VALUES
    ('device1', 'user1', 'Device 1'),
    ('device2', 'user1', 'Device 2');
*/
@Entity
@Table(name = "user")
public class User extends PanacheEntityBase {

	@Id
	@Column(name = "id", nullable = false)
	public String id;

	@OneToMany(mappedBy = "owner")
	public Set<Device> devices = new HashSet<>();

	@Column(name = "name", nullable = false)
	public String name;

	/* hashcode/equals/etc */

}
/*
@Entity
@Table(name = "device")
public class Device extends PanacheEntityBase {

	@Id
	@Column(name = "id", nullable = false)
	public String id;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "user_id", updatable = false, nullable = false)
	public User owner;

	@Column(name = "name", nullable = false)
	public String name;

	/ * hashcode/equals/etc */
*/
}

Output of uname -a or ver

Darwin Kernel Version 20.6.0

Output of java -version

OpenJDK Runtime Environment Temurin-17+35 (build 17+35)

GraalVM version (if different from Java)

N/A

Quarkus version or git rev

2.5.0.Final

Build tool (ie. output of mvnw --version or gradlew --version)

Maven 3.8.3

Additional information

No response

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:10 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
overheadhuntercommented, Nov 30, 2021

You can likely use:

@Inject 
UserTransaction transaction;

in your and manually handle the transaction boundaries as is described here.

I can confirm this works in nested tests. For now this should be a feasible workaround.

1reaction
geoandcommented, Nov 30, 2021

Btw I believe #20034 is about @TestTransactions.

Yeah, but the root cause it likely the same - JUnit does not allow us to control the lifecycle of the nested test

Read more comments on GitHub >

github_iconTop Results From Across the Web

Transaction roll back is not working in test case in @Nested ...
This is to be expected: the Spring TestContext Framework has never supported "inheritance" for nested test classes.
Read more >
Don't Use @Transactional in Tests - DEV Community ‍ ‍
@Transactional enables undesired behaviors that produce false negatives in our test suite, which can impact the confidence developers have to ...
Read more >
Testing guice-persist nested @Transactional behavior
As it turns out, Guice seems ignore any of nested @Transactional and any of its rollbackOn attributes. It's all up to the parent...
Read more >
Discover test configuration on enclosing class for nested test ...
One context is started for TwoDifferentContextsTests . Due to @SpringBootTest , it finds the @SpringBootApplication -annotated class and uses that as the ...
Read more >
Spring Transactional – 5 Common Pitfalls | Codete Blog
Have you ever annotated a method with @Transactional (or e.g. @Async) and it didn't work? As if it was totally ignored by Spring?...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found