Skip to content

Commit 2000c5a

Browse files
committed
Force the flush of the EntityManager before the assertion if a transaction is running in the test
1 parent e4579bc commit 2000c5a

File tree

2 files changed

+65
-11
lines changed

2 files changed

+65
-11
lines changed

src/main/java/com/lemick/integration/spring/HibernateStatementCountTestListener.java

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
import com.lemick.assertions.HibernateStatementAssertionsProvider;
77
import com.lemick.integration.hibernate.HibernateStatementCountInspector;
88
import com.lemick.integration.hibernate.HibernateStatistics;
9+
import jakarta.persistence.EntityManager;
910
import org.springframework.core.Ordered;
1011
import org.springframework.test.context.TestContext;
1112
import org.springframework.test.context.TestExecutionListener;
13+
import org.springframework.test.context.transaction.TestTransaction;
1214

1315
import java.util.List;
1416
import java.util.function.Supplier;
@@ -17,6 +19,8 @@ public class HibernateStatementCountTestListener implements TestExecutionListene
1719

1820
private HibernateStatementAssertionsProvider hibernateStatementAssertionsProvider = new HibernateStatementAssertionsProvider();
1921
private Supplier<HibernateStatistics> statisticsSupplier = HibernateStatementCountInspector::getStatistics;
22+
private Supplier<Boolean> transactionAvailabilitySupplier = TestTransaction::isActive;
23+
2024

2125
@Override
2226
public void beforeTestMethod(TestContext testContext) {
@@ -27,18 +31,38 @@ public void beforeTestMethod(TestContext testContext) {
2731
public void afterTestMethod(TestContext testContext) {
2832
AssertHibernateSQLStatementCount annotation = testContext.getTestMethod().getAnnotation(AssertHibernateSQLStatementCount.class);
2933
if (annotation != null) {
30-
HibernateStatementAssertionResults assertionResults = new HibernateStatementAssertionResults(List.of(
31-
hibernateStatementAssertionsProvider.generateSelectStatementAssertion(annotation.selects(), statisticsSupplier),
32-
hibernateStatementAssertionsProvider.generateUpdateStatementAssertion(annotation.updates(), statisticsSupplier),
33-
hibernateStatementAssertionsProvider.generateInsertStatementAssertion(annotation.inserts(), statisticsSupplier),
34-
hibernateStatementAssertionsProvider.generateDeleteStatementAssertion(annotation.deletes(), statisticsSupplier)
35-
));
36-
assertionResults.validate();
34+
flushExistingPersistenceContext(testContext, transactionAvailabilitySupplier);
35+
doStatementCountEvaluation(annotation);
3736
}
3837
}
3938

39+
40+
/**
41+
* Low precedence for executing before {@link org.springframework.test.context.transaction.TransactionalTestExecutionListener}
42+
* closes the transaction and have the ability to flush the EntityManager
43+
*/
4044
@Override
4145
public int getOrder() {
42-
return Integer.MIN_VALUE;
46+
return Ordered.LOWEST_PRECEDENCE;
47+
}
48+
49+
private void flushExistingPersistenceContext(TestContext testContext, Supplier<Boolean> transactionAvailabilitySupplier) {
50+
if (transactionAvailabilitySupplier.get()) {
51+
testContext.getApplicationContext()
52+
.getAutowireCapableBeanFactory()
53+
.getBean(EntityManager.class)
54+
.flush();
55+
}
56+
}
57+
58+
private void doStatementCountEvaluation(AssertHibernateSQLStatementCount annotation) {
59+
HibernateStatementAssertionResults assertionResults = new HibernateStatementAssertionResults(List.of(
60+
hibernateStatementAssertionsProvider.generateSelectStatementAssertion(annotation.selects(), statisticsSupplier),
61+
hibernateStatementAssertionsProvider.generateUpdateStatementAssertion(annotation.updates(), statisticsSupplier),
62+
hibernateStatementAssertionsProvider.generateInsertStatementAssertion(annotation.inserts(), statisticsSupplier),
63+
hibernateStatementAssertionsProvider.generateDeleteStatementAssertion(annotation.deletes(), statisticsSupplier)
64+
));
65+
assertionResults.validate();
4366
}
67+
4468
}

src/test/java/com/lemick/integration/spring/HibernateStatementCountTestListenerTest.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
import com.lemick.assertions.HibernateStatementAssertionResult;
55
import com.lemick.assertions.HibernateStatementAssertionsProvider;
66
import com.lemick.integration.hibernate.HibernateStatistics;
7+
import jakarta.persistence.EntityManager;
8+
import jakarta.transaction.Transactional;
79
import org.junit.jupiter.api.Test;
810
import org.junit.jupiter.api.extension.ExtendWith;
11+
import org.mockito.Answers;
912
import org.mockito.InjectMocks;
1013
import org.mockito.Mock;
1114
import org.mockito.Spy;
@@ -19,7 +22,7 @@
1922
@ExtendWith(MockitoExtension.class)
2023
class HibernateStatementCountTestListenerTest {
2124

22-
public class FakeClass {
25+
public static class FakeClass {
2326
@AssertHibernateSQLStatementCount(inserts = 1, deletes = 2, selects = 3, updates = 4)
2427
public void annotatedMethod() {
2528

@@ -40,6 +43,9 @@ public void notAnnotatedMethod() {
4043
Supplier<HibernateStatistics> statisticsSupplier;
4144

4245
@Mock
46+
Supplier<Boolean> transactionAvailabilitySupplier;
47+
48+
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
4349
TestContext testContext;
4450

4551
@Test
@@ -61,7 +67,7 @@ public void _beforeTestMethod_with_annotation() {
6167
}
6268

6369
@Test
64-
public void _afterTestMethod_no_annotation() throws NoSuchMethodException {
70+
public void _afterTestMethod_without_annotation() throws NoSuchMethodException {
6571
when(testContext.getTestMethod()).thenReturn(FakeClass.class.getMethod("notAnnotatedMethod"));
6672

6773
model.afterTestMethod(testContext);
@@ -73,8 +79,31 @@ public void _afterTestMethod_no_annotation() throws NoSuchMethodException {
7379
}
7480

7581
@Test
76-
public void _afterTestMethod_with_annotation() throws NoSuchMethodException {
82+
public void _afterTestMethod_with_annotation_without_transaction() throws NoSuchMethodException {
83+
when(testContext.getTestMethod()).thenReturn(FakeClass.class.getMethod("annotatedMethod"));
84+
when(transactionAvailabilitySupplier.get()).thenReturn(false);
85+
86+
HibernateStatementAssertionResult statementAssertionResult = mock(HibernateStatementAssertionResult.class);
87+
when(hibernateStatementAssertUtils.generateInsertStatementAssertion(anyInt(), any())).thenReturn(statementAssertionResult);
88+
when(hibernateStatementAssertUtils.generateSelectStatementAssertion(anyInt(), any())).thenReturn(statementAssertionResult);
89+
when(hibernateStatementAssertUtils.generateUpdateStatementAssertion(anyInt(), any())).thenReturn(statementAssertionResult);
90+
when(hibernateStatementAssertUtils.generateDeleteStatementAssertion(anyInt(), any())).thenReturn(statementAssertionResult);
91+
92+
model.afterTestMethod(testContext);
93+
94+
verify(testContext, times(0).description("EntityManager is NOT flushed")).getApplicationContext();
95+
verify(hibernateStatementAssertUtils, description("assert method is called")).generateSelectStatementAssertion(3, statisticsSupplier);
96+
verify(hibernateStatementAssertUtils, description("assert method is called")).generateUpdateStatementAssertion(4, statisticsSupplier);
97+
verify(hibernateStatementAssertUtils, description("assert method is called")).generateInsertStatementAssertion(1, statisticsSupplier);
98+
verify(hibernateStatementAssertUtils, description("assert method is called")).generateDeleteStatementAssertion(2, statisticsSupplier);
99+
}
100+
101+
@Test
102+
public void _afterTestMethod_with_annotation_with_transaction() throws NoSuchMethodException {
103+
EntityManager entityManager = mock(EntityManager.class);
77104
when(testContext.getTestMethod()).thenReturn(FakeClass.class.getMethod("annotatedMethod"));
105+
when(testContext.getApplicationContext().getAutowireCapableBeanFactory().getBean(EntityManager.class)).thenReturn(entityManager);
106+
when(transactionAvailabilitySupplier.get()).thenReturn(true);
78107

79108
HibernateStatementAssertionResult statementAssertionResult = mock(HibernateStatementAssertionResult.class);
80109
when(hibernateStatementAssertUtils.generateInsertStatementAssertion(anyInt(), any())).thenReturn(statementAssertionResult);
@@ -84,6 +113,7 @@ public void _afterTestMethod_with_annotation() throws NoSuchMethodException {
84113

85114
model.afterTestMethod(testContext);
86115

116+
verify(entityManager, description("EntityManager is flushed")).flush();
87117
verify(hibernateStatementAssertUtils, description("assert method is called")).generateSelectStatementAssertion(3, statisticsSupplier);
88118
verify(hibernateStatementAssertUtils, description("assert method is called")).generateUpdateStatementAssertion(4, statisticsSupplier);
89119
verify(hibernateStatementAssertUtils, description("assert method is called")).generateInsertStatementAssertion(1, statisticsSupplier);

0 commit comments

Comments
 (0)