View Javadoc
1   /*
2    *
3    * The DbUnit Database Testing Framework
4    * Copyright (C)2002-2026, DbUnit.org
5    *
6    * This library is free software; you can redistribute it and/or
7    * modify it under the terms of the GNU Lesser General Public
8    * License as published by the Free Software Foundation; either
9    * version 2.1 of the License, or (at your option) any later version.
10   *
11   * This library is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   * Lesser General Public License for more details.
15   *
16   * You should have received a copy of the GNU Lesser General Public
17   * License along with this library; if not, write to the Free Software
18   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19   *
20   */
21  package org.dbunit.junit.jupiter;
22  
23  import static org.assertj.core.api.Assertions.assertThat;
24  import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
25  
26  import java.util.ArrayList;
27  import java.util.List;
28  
29  import org.dbunit.DatabaseEnvironment;
30  import org.dbunit.DefaultDatabaseTester;
31  import org.dbunit.DefaultPrepAndExpectedTestCase;
32  import org.dbunit.IDatabaseTester;
33  import org.dbunit.IOperationListener;
34  import org.dbunit.PrepAndExpectedTestCase;
35  import org.dbunit.annotation.DbUnitConfig;
36  import org.dbunit.annotation.DbUnitExpected;
37  import org.dbunit.annotation.DbUnitPrep;
38  import org.dbunit.annotation.DbUnitProperty;
39  import org.dbunit.annotation.DbUnitTestCase;
40  import org.dbunit.annotation.DbUnitTester;
41  import org.dbunit.database.DatabaseConfig;
42  import org.dbunit.database.IDatabaseConnection;
43  import org.dbunit.util.fileloader.FlatXmlDataFileLoader;
44  import org.junit.jupiter.api.Test;
45  import org.junit.jupiter.api.extension.ExtendWith;
46  import org.junit.platform.testkit.engine.EngineTestKit;
47  
48  /**
49   * Real-database integration test proving an {@code @DbUnitProperty} value actually reaches
50   * {@link IDatabaseConnection#getConfig()} on both the setup/teardown path (the {@code
51   * IOperationListener} wiring described in the annotations plan's execution model) and the
52   * prep/expected path ({@code DefaultPrepAndExpectedTestCase}'s own connection resolution,
53   * which never goes through that listener) - neither is something
54   * {@code AnnotatedTestExecutorTest}'s mocked connection can prove - and that a connection kept
55   * open past the test carries the value into no later test.
56   */
57  class DbUnitConfigPropertiesIT
58  {
59      @Test
60      void testBeforeTestExecution_dbUnitPropertyDeclared_reachesConnectionConfig()
61              throws Exception
62      {
63          final DatabaseEnvironment environment = DatabaseEnvironment.getInstance();
64          try
65          {
66              final IDatabaseConnection connection = environment.getConnection();
67              connection.getConfig().setFeature(DatabaseConfig.FEATURE_BATCHED_STATEMENTS, false);
68              PropertySample.databaseTester = new DefaultDatabaseTester(connection);
69              PropertySample.databaseTester
70                      .setOperationListener(IOperationListener.NO_OP_OPERATION_LISTENER);
71  
72              EngineTestKit.engine("junit-jupiter").selectors(selectClass(PropertySample.class))
73                      .execute().testEvents()
74                      .assertStatistics(stats -> stats.started(1).succeeded(1));
75  
76              assertThat(PropertySample.batchedStatementsDuringTest)
77                      .as("The @DbUnitProperty value must be applied to the real connection's"
78                              + " DatabaseConfig while the test runs.")
79                      .isTrue();
80              assertThat(
81                      connection.getConfig().getFeature(DatabaseConfig.FEATURE_BATCHED_STATEMENTS))
82                              .as("The connection is kept open past the test, so the value must be"
83                                      + " put back for whatever uses it next.")
84                              .isFalse();
85          } finally
86          {
87              environment.closeConnection();
88          }
89      }
90  
91      @ExtendWith(DbUnitExtension.class)
92      // closeConnectionAfterTest = false: databaseTester wraps the environment's shared
93      // connection (see the finally block above), not one owned by this one test.
94      @DbUnitConfig(closeConnectionAfterTest = false,
95              properties = @DbUnitProperty(name = "batchedStatements", value = "true"))
96      @DbUnitPrep("empty.xml")
97      static class PropertySample
98      {
99          @DbUnitTester
100         static IDatabaseTester databaseTester;
101 
102         static boolean batchedStatementsDuringTest;
103 
104         @Test
105         void testPropertyIsAppliedBeforeTheTestRuns() throws Exception
106         {
107             final DatabaseConfig config = databaseTester.getConnection().getConfig();
108             batchedStatementsDuringTest =
109                     config.getFeature(DatabaseConfig.FEATURE_BATCHED_STATEMENTS);
110         }
111     }
112 
113     @Test
114     void testBeforeTestExecution_dbUnitPropertyDeclaredOnExpectedPath_reachesConnectionConfig()
115             throws Exception
116     {
117         final DatabaseEnvironment environment = DatabaseEnvironment.getInstance();
118         try
119         {
120             final IDatabaseConnection connection = environment.getConnection();
121             connection.getConfig().setFeature(DatabaseConfig.FEATURE_BATCHED_STATEMENTS, false);
122             ExpectedPathPropertySample.databaseTester = new DefaultDatabaseTester(connection);
123             ExpectedPathPropertySample.databaseTester
124                     .setOperationListener(IOperationListener.NO_OP_OPERATION_LISTENER);
125 
126             EngineTestKit.engine("junit-jupiter")
127                     .selectors(selectClass(ExpectedPathPropertySample.class)).execute()
128                     .testEvents().assertStatistics(stats -> stats.started(1).succeeded(1));
129 
130             assertThat(ExpectedPathPropertySample.batchedStatementsDuringTest)
131                     .as("The @DbUnitProperty value must reach the connection"
132                             + " DefaultPrepAndExpectedTestCase actually uses for"
133                             + " setupData()/verifyData()/cleanupData() - the"
134                             + " setup/teardown path's IOperationListener wiring is never"
135                             + " triggered by those methods.")
136                     .isTrue();
137             assertThat(
138                     connection.getConfig().getFeature(DatabaseConfig.FEATURE_BATCHED_STATEMENTS))
139                             .as("The connection is kept open past the test, so the value must be"
140                                     + " put back for whatever uses it next - including when the"
141                                     + " test method took the connection as a parameter.")
142                             .isFalse();
143         } finally
144         {
145             environment.closeConnection();
146         }
147     }
148 
149     @ExtendWith(DbUnitExtension.class)
150     // closeConnectionAfterTest = false: databaseTester wraps the environment's shared
151     // connection (see the finally block above), not one owned by this one test.
152     @DbUnitConfig(closeConnectionAfterTest = false,
153             properties = @DbUnitProperty(name = "batchedStatements", value = "true"))
154     @DbUnitExpected("empty.xml")
155     static class ExpectedPathPropertySample
156     {
157         @DbUnitTester
158         static IDatabaseTester databaseTester;
159 
160         static boolean batchedStatementsDuringTest;
161 
162         @Test
163         void testPropertyIsAppliedBeforeVerification(final IDatabaseConnection connection)
164         {
165             batchedStatementsDuringTest = connection.getConfig()
166                     .getFeature(DatabaseConfig.FEATURE_BATCHED_STATEMENTS);
167         }
168     }
169 
170     @Test
171     void testAfterTestExecution_testCaseKeepsItsConnectionAcrossTests_eachTestSeesOnlyItsOwnProperties()
172             throws Exception
173     {
174         final DatabaseEnvironment environment = DatabaseEnvironment.getInstance();
175         try
176         {
177             final IDatabaseConnection connection = environment.getConnection();
178             KeptConnectionBase.observedBatchSizes.clear();
179             KeptConnectionBase.testCase = new DefaultPrepAndExpectedTestCase(
180                     new FlatXmlDataFileLoader(), new DefaultDatabaseTester(connection), false);
181 
182             runOnTheKeptConnection(DeclaresNothingFirst.class);
183             runOnTheKeptConnection(DeclaresBatchSize.class);
184             runOnTheKeptConnection(DeclaresNothingLast.class);
185 
186             final Object defaultBatchSize =
187                     new DatabaseConfig().getProperty(DatabaseConfig.PROPERTY_BATCH_SIZE);
188             assertThat(KeptConnectionBase.observedBatchSizes)
189                     .as("A test declaring nothing, then one declaring batchSize=50, then one"
190                             + " declaring nothing again, on one connection kept across them:"
191                             + " the middle value must not bleed into the last test.")
192                     .containsExactly(defaultBatchSize, 50, defaultBatchSize);
193             assertThat(connection.getConfig().getProperty(DatabaseConfig.PROPERTY_BATCH_SIZE))
194                     .as("Nothing is left on the connection once the last test is done.")
195                     .isEqualTo(defaultBatchSize);
196         } finally
197         {
198             environment.closeConnection();
199         }
200     }
201 
202     private static void runOnTheKeptConnection(final Class<?> sampleClass)
203     {
204         EngineTestKit.engine("junit-jupiter").selectors(selectClass(sampleClass)).execute()
205                 .testEvents().assertStatistics(stats -> stats.started(1).succeeded(1));
206     }
207 
208     static class KeptConnectionBase
209     {
210         @DbUnitTestCase
211         static PrepAndExpectedTestCase testCase;
212 
213         static final List<Object> observedBatchSizes = new ArrayList<>();
214 
215         @Test
216         @DbUnitExpected("empty.xml")
217         void testObservesBatchSize(final IDatabaseConnection connection)
218         {
219             observedBatchSizes
220                     .add(connection.getConfig().getProperty(DatabaseConfig.PROPERTY_BATCH_SIZE));
221         }
222     }
223 
224     @ExtendWith(DbUnitExtension.class)
225     static class DeclaresNothingFirst extends KeptConnectionBase
226     {
227     }
228 
229     @ExtendWith(DbUnitExtension.class)
230     @DbUnitConfig(properties = @DbUnitProperty(name = "batchSize", value = "50"))
231     static class DeclaresBatchSize extends KeptConnectionBase
232     {
233     }
234 
235     @ExtendWith(DbUnitExtension.class)
236     static class DeclaresNothingLast extends KeptConnectionBase
237     {
238     }
239 }