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.sql.Connection;
27  import java.sql.ResultSet;
28  import java.sql.Statement;
29  import java.util.ArrayList;
30  import java.util.List;
31  
32  import org.dbunit.DatabaseEnvironment;
33  import org.dbunit.DatabaseProfile;
34  import org.dbunit.DatabaseTesterFactory;
35  import org.dbunit.DefaultDatabaseTester;
36  import org.dbunit.DefaultPrepAndExpectedTestCase;
37  import org.dbunit.IDatabaseTester;
38  import org.dbunit.IOperationListener;
39  import org.dbunit.JdbcDatabaseTester;
40  import org.dbunit.PrepAndExpectedTestCase;
41  import org.dbunit.annotation.DbUnitConfig;
42  import org.dbunit.annotation.DbUnitExpected;
43  import org.dbunit.annotation.DbUnitPrep;
44  import org.dbunit.annotation.DbUnitSetup;
45  import org.dbunit.annotation.DbUnitTearDown;
46  import org.dbunit.annotation.DbUnitTestCase;
47  import org.dbunit.annotation.DbUnitTester;
48  import org.dbunit.annotation.DbUnitVerifyTable;
49  import org.dbunit.database.CachingConnectionProvider;
50  import org.dbunit.database.IDatabaseConnection;
51  import org.dbunit.operation.DbUnitOperation;
52  import org.junit.jupiter.api.Test;
53  import org.junit.jupiter.api.extension.ExtendWith;
54  import org.junit.platform.testkit.engine.EngineTestKit;
55  
56  /**
57   * Real-database (hsqldb) integration test of the annotation-driven path through
58   * {@link DbUnitExtension}: {@code @DbUnitPrep} seeds, the test mutates, {@code @DbUnitExpected}
59   * verifies, and {@code @DbUnitTearDown} cleans up - plus a class-level {@code @DbUnitSetup}
60   * operation staying in force across a method that declares its own {@code @DbUnitPrep}, the
61   * override trap the split between the two annotations exists to prevent - and the
62   * {@code @DbUnitTestCase}/{@code databaseTesterFactory()} resolution tiers, which
63   * {@code AnnotatedTestExecutorTest}'s mocked tester/test case cannot prove actually drive a real
64   * connection end to end.
65   */
66  class DbUnitExtensionAnnotationIT
67  {
68      private static final String TEST_TABLE = "TEST_TABLE";
69      private static final String PK_TABLE = "PK_TABLE";
70  
71      @Test
72      void testAfterTestExecution_prepMutateExpected_verifiesAndCleansUp() throws Exception
73      {
74          final DatabaseEnvironment environment = DatabaseEnvironment.getInstance();
75          try
76          {
77              final IDatabaseConnection connection = environment.getConnection();
78              PrepExpectedSample.databaseTester = new DefaultDatabaseTester(connection);
79              PrepExpectedSample.databaseTester
80                      .setOperationListener(IOperationListener.NO_OP_OPERATION_LISTENER);
81  
82              EngineTestKit.engine("junit-jupiter")
83                      .selectors(selectClass(PrepExpectedSample.class)).execute().testEvents()
84                      .assertStatistics(stats -> stats.started(1).succeeded(1));
85  
86              // the prep/expected path closes its own connection when the test finishes
87              // (closeConnectionAfterTest defaults to true), so verify with a fresh one.
88              final IDatabaseConnection verifyConnection = environment.getConnection();
89              assertThat(rowCount(verifyConnection, TEST_TABLE))
90                      .as("@DbUnitTearDown(operation = DELETE_ALL) must have cleaned up.")
91                      .isZero();
92          } finally
93          {
94              deleteAllRowsQuietly(environment, TEST_TABLE);
95              environment.closeConnection();
96          }
97      }
98  
99      @Test
100     void testAfterTestExecution_jsonPrepAndExpectedFiles_verifiesAndCleansUp() throws Exception
101     {
102         final DatabaseEnvironment environment = DatabaseEnvironment.getInstance();
103         try
104         {
105             final IDatabaseConnection connection = environment.getConnection();
106             JsonPrepExpectedSample.databaseTester = new DefaultDatabaseTester(connection);
107             JsonPrepExpectedSample.databaseTester
108                     .setOperationListener(IOperationListener.NO_OP_OPERATION_LISTENER);
109 
110             EngineTestKit.engine("junit-jupiter")
111                     .selectors(selectClass(JsonPrepExpectedSample.class)).execute().testEvents()
112                     .assertStatistics(stats -> stats.started(1).succeeded(1));
113 
114             final IDatabaseConnection verifyConnection = environment.getConnection();
115             assertThat(rowCount(verifyConnection, TEST_TABLE))
116                     .as("The prep/expected path must load a JSON @DbUnitPrep and @DbUnitExpected"
117                             + " file through the default FileExtensionDataFileLoader (dispatched"
118                             + " by the .json extension to JsonDataFileLoader), verify, and run"
119                             + " @DbUnitTearDown(DELETE_ALL) - end to end, the same as flat XML.")
120                     .isZero();
121         } finally
122         {
123             deleteAllRowsQuietly(environment, TEST_TABLE);
124             environment.closeConnection();
125         }
126     }
127 
128     @Test
129     void testBeforeTestExecution_classLevelSetupOperation_survivesMethodLevelPrep()
130             throws Exception
131     {
132         final DatabaseEnvironment environment = DatabaseEnvironment.getInstance();
133         try
134         {
135             final IDatabaseConnection connection = environment.getConnection();
136             ClassLevelOperationSample.databaseTester = new DefaultDatabaseTester(connection);
137             ClassLevelOperationSample.databaseTester
138                     .setOperationListener(IOperationListener.NO_OP_OPERATION_LISTENER);
139             try (Statement statement = connection.getConnection().createStatement())
140             {
141                 statement.execute("INSERT INTO " + PK_TABLE
142                         + " (PK0, PK1, PK2, NORMAL0) VALUES (997, 997, 997, 'preexisting')");
143             }
144 
145             EngineTestKit.engine("junit-jupiter")
146                     .selectors(selectClass(ClassLevelOperationSample.class)).execute()
147                     .testEvents().assertStatistics(stats -> stats.started(1).succeeded(1));
148 
149             assertThat(rowCountForPks(connection, 997, 998))
150                     .as("REFRESH (an upsert) must not have wiped the pre-existing row (PK 997)"
151                             + " the way CLEAN_INSERT would have; the class-level @DbUnitSetup"
152                             + " operation must have survived the method's own @DbUnitPrep"
153                             + " (which seeds PK 998).")
154                     .isEqualTo(2);
155         } finally
156         {
157             deletePksQuietly(environment, 997, 998);
158             environment.closeConnection();
159         }
160     }
161 
162     @Test
163     void testBeforeTestExecution_expectedPathClassLevelSetupOperation_survivesMethodLevelPrep()
164             throws Exception
165     {
166         final DatabaseEnvironment environment = DatabaseEnvironment.getInstance();
167         try
168         {
169             final IDatabaseConnection connection = environment.getConnection();
170             ExpectedPathClassLevelOperationSample.databaseTester =
171                     new DefaultDatabaseTester(connection);
172             ExpectedPathClassLevelOperationSample.databaseTester
173                     .setOperationListener(IOperationListener.NO_OP_OPERATION_LISTENER);
174             try (Statement statement = connection.getConnection().createStatement())
175             {
176                 statement.execute("INSERT INTO " + PK_TABLE
177                         + " (PK0, PK1, PK2, NORMAL0) VALUES (895, 895, 895, 'preexisting')");
178             }
179 
180             EngineTestKit.engine("junit-jupiter")
181                     .selectors(selectClass(ExpectedPathClassLevelOperationSample.class)).execute()
182                     .testEvents().assertStatistics(stats -> stats.started(1).succeeded(1));
183 
184             assertThat(rowCountForPks(connection, 895, 998))
185                     .as("REFRESH (an upsert) must not have wiped the pre-existing row (PK 895)"
186                             + " the way CLEAN_INSERT would have; the class-level @DbUnitSetup"
187                             + " operation must apply on the @DbUnitExpected prep/expected path"
188                             + " too, the same as it already does on the setup/teardown path.")
189                     .isEqualTo(2);
190         } finally
191         {
192             deletePksQuietly(environment, 895, 998);
193             environment.closeConnection();
194         }
195     }
196 
197     @Test
198     void testAfterTestExecution_injectedTestCaseAndFactoryResolvedTester_verifiesAndCleansUp()
199             throws Exception
200     {
201         final DatabaseEnvironment environment = DatabaseEnvironment.getInstance();
202         try
203         {
204             EngineTestKit.engine("junit-jupiter")
205                     .selectors(selectClass(InjectedTestCaseSample.class)).execute().testEvents()
206                     .assertStatistics(stats -> stats.started(1).succeeded(1));
207 
208             // the prep/expected path closes its own connection when the test finishes
209             // (closeConnectionAfterTest defaults to true), so verify with a fresh one.
210             final IDatabaseConnection verifyConnection = environment.getConnection();
211             assertThat(rowCount(verifyConnection, TEST_TABLE))
212                     .as("@DbUnitTearDown(operation = DELETE_ALL), driven through the"
213                             + " @DbUnitTestCase-injected PrepAndExpectedTestCase and a"
214                             + " databaseTesterFactory-resolved tester, must have cleaned up.")
215                     .isZero();
216         } finally
217         {
218             deleteAllRowsQuietly(environment, TEST_TABLE);
219             environment.closeConnection();
220         }
221     }
222 
223     @Test
224     void testAfterTestExecution_realJdbcDatabaseTesterExpectedPath_verifiesAndCleansUp()
225             throws Exception
226     {
227         final DatabaseEnvironment environment = DatabaseEnvironment.getInstance();
228         try
229         {
230             JdbcTesterExpectedPathSample.databaseTester = newJdbcDatabaseTester(environment);
231 
232             EngineTestKit.engine("junit-jupiter")
233                     .selectors(selectClass(JdbcTesterExpectedPathSample.class)).execute()
234                     .testEvents().assertStatistics(stats -> stats.started(1).succeeded(1));
235 
236             final IDatabaseConnection verifyConnection = environment.getConnection();
237             assertThat(rowCount(verifyConnection, TEST_TABLE))
238                     .as("The prep/expected path driven through a real JdbcDatabaseTester - a"
239                             + " fresh physical connection per getConnection() call, its default"
240                             + " DefaultOperationListener wrapped by the extension, not a"
241                             + " NO_OP-listener DefaultDatabaseTester as the samples above use -"
242                             + " must still run setup, verify (against an injected Connection's"
243                             + " mutation), and @DbUnitTearDown(DELETE_ALL) end to end.")
244                     .isZero();
245         } finally
246         {
247             deleteAllRowsQuietly(environment, TEST_TABLE);
248             environment.closeConnection();
249         }
250     }
251 
252     @Test
253     void testAfterTestExecution_realJdbcDatabaseTesterSetupTeardownPath_setsUpAndTearsDown()
254             throws Exception
255     {
256         final DatabaseEnvironment environment = DatabaseEnvironment.getInstance();
257         try
258         {
259             JdbcTesterSetupTeardownPathSample.databaseTester = newJdbcDatabaseTester(environment);
260 
261             EngineTestKit.engine("junit-jupiter")
262                     .selectors(selectClass(JdbcTesterSetupTeardownPathSample.class)).execute()
263                     .testEvents().assertStatistics(stats -> stats.started(1).succeeded(1));
264 
265             final IDatabaseConnection verifyConnection = environment.getConnection();
266             assertThat(rowCount(verifyConnection, TEST_TABLE))
267                     .as("The setup/teardown path driven through a real JdbcDatabaseTester - where the"
268                             + " extension's ExecutorOperationListener wraps the tester's own"
269                             + " DefaultOperationListener, the row count baseline piggybacks on"
270                             + " onSetup()'s connection, and onTearDown() opens a different one -"
271                             + " must still apply @DbUnitPrep and @DbUnitTearDown(DELETE_ALL) end"
272                             + " to end.")
273                     .isZero();
274         } finally
275         {
276             deleteAllRowsQuietly(environment, TEST_TABLE);
277             environment.closeConnection();
278         }
279     }
280 
281     @Test
282     void testAfterTestExecution_cachingProviderAndCloseConnectionAfterTestFalse_reusesConnectionAcrossMethods()
283             throws Exception
284     {
285         final DatabaseEnvironment environment = DatabaseEnvironment.getInstance();
286         final DatabaseProfile profile = environment.getProfile();
287         final CachingConnectionProvider provider = new CachingConnectionProvider();
288         CachingProviderSample.connectionsSeen.clear();
289         try
290         {
291             CachingProviderSample.databaseTester = new JdbcDatabaseTester(
292                     profile.getDriverClass(), profile.getConnectionUrl(), profile.getUser(),
293                     profile.getPassword(), profile.getSchema(), provider);
294 
295             EngineTestKit.engine("junit-jupiter")
296                     .selectors(selectClass(CachingProviderSample.class)).execute().testEvents()
297                     .assertStatistics(stats -> stats.started(2).succeeded(2));
298 
299             assertThat(CachingProviderSample.connectionsSeen)
300                     .as("@DbUnitConfig(closeConnectionAfterTest = false) with a"
301                             + " CachingConnectionProvider must hand both test methods the same"
302                             + " physical Connection - the extension must not close the cached"
303                             + " connection after the first test.")
304                     .hasSize(2)
305                     .satisfies(seen -> assertThat(seen.get(0)).isSameAs(seen.get(1)));
306         } finally
307         {
308             deleteAllRowsQuietly(environment, TEST_TABLE);
309             provider.close();
310             environment.closeConnection();
311         }
312     }
313 
314     private static IDatabaseTester newJdbcDatabaseTester(final DatabaseEnvironment environment)
315             throws Exception
316     {
317         final DatabaseProfile profile = environment.getProfile();
318         return new JdbcDatabaseTester(profile.getDriverClass(), profile.getConnectionUrl(),
319                 profile.getUser(), profile.getPassword(), profile.getSchema());
320     }
321 
322     private static int rowCount(final IDatabaseConnection connection, final String tableName)
323             throws Exception
324     {
325         try (Statement statement = connection.getConnection().createStatement();
326                 ResultSet resultSet =
327                         statement.executeQuery("SELECT COUNT(*) FROM " + tableName))
328         {
329             resultSet.next();
330             return resultSet.getInt(1);
331         }
332     }
333 
334     private static int rowCountForPks(final IDatabaseConnection connection, final int... pk0s)
335             throws Exception
336     {
337         final String inList = pkInList(pk0s);
338         try (Statement statement = connection.getConnection().createStatement();
339                 ResultSet resultSet = statement.executeQuery(
340                         "SELECT COUNT(*) FROM " + PK_TABLE + " WHERE PK0 IN (" + inList + ")"))
341         {
342             resultSet.next();
343             return resultSet.getInt(1);
344         }
345     }
346 
347     private static String pkInList(final int... pk0s)
348     {
349         final StringBuilder inList = new StringBuilder();
350         for (int i = 0; i < pk0s.length; i++)
351         {
352             if (i > 0)
353             {
354                 inList.append(',');
355             }
356             inList.append(pk0s[i]);
357         }
358         return inList.toString();
359     }
360 
361     private static void deleteAllRowsQuietly(final DatabaseEnvironment environment,
362             final String tableName)
363     {
364         try (Statement statement =
365                 environment.getConnection().getConnection().createStatement())
366         {
367             statement.execute("DELETE FROM " + tableName);
368         } catch (final Exception e)
369         {
370             // best-effort cleanup only; a failure here must not fail the test that already ran
371         }
372     }
373 
374     private static void deletePksQuietly(final DatabaseEnvironment environment,
375             final int... pk0s)
376     {
377         final String inList = pkInList(pk0s);
378         try (Statement statement =
379                 environment.getConnection().getConnection().createStatement())
380         {
381             statement.execute("DELETE FROM " + PK_TABLE + " WHERE PK0 IN (" + inList + ")");
382         } catch (final Exception e)
383         {
384             // best-effort cleanup only; a failure here must not fail the test that already ran
385         }
386     }
387 
388     @ExtendWith(DbUnitExtension.class)
389     static class PrepExpectedSample
390     {
391         @DbUnitTester
392         static IDatabaseTester databaseTester;
393 
394         @Test
395         @DbUnitPrep("annotation-it-prep.xml")
396         @DbUnitExpected(value = "annotation-it-expected.xml",
397                 verify = @DbUnitVerifyTable(value = TEST_TABLE,
398                         include = {"COLUMN0", "COLUMN1"}))
399         @DbUnitTearDown(operation = DbUnitOperation.DELETE_ALL)
400         void testWithdraw_sufficientBalance_decrementsBalance() throws Exception
401         {
402             try (Statement statement =
403                     databaseTester.getConnection().getConnection().createStatement())
404             {
405                 statement.execute(
406                         "UPDATE " + TEST_TABLE + " SET COLUMN1 = 'after' WHERE COLUMN0 = 'row0'");
407             }
408         }
409     }
410 
411     @ExtendWith(DbUnitExtension.class)
412     static class JsonPrepExpectedSample
413     {
414         @DbUnitTester
415         static IDatabaseTester databaseTester;
416 
417         @Test
418         @DbUnitPrep("annotation-it-prep.json")
419         @DbUnitExpected(value = "annotation-it-expected.json",
420                 verify = @DbUnitVerifyTable(value = TEST_TABLE,
421                         include = {"COLUMN0", "COLUMN1"}))
422         @DbUnitTearDown(operation = DbUnitOperation.DELETE_ALL)
423         void testWithdraw_sufficientBalance_decrementsBalance() throws Exception
424         {
425             try (Statement statement =
426                     databaseTester.getConnection().getConnection().createStatement())
427             {
428                 statement.execute(
429                         "UPDATE " + TEST_TABLE + " SET COLUMN1 = 'after' WHERE COLUMN0 = 'row0'");
430             }
431         }
432     }
433 
434     @ExtendWith(DbUnitExtension.class)
435     static class JdbcTesterExpectedPathSample
436     {
437         @DbUnitTester
438         static IDatabaseTester databaseTester;
439 
440         @Test
441         @DbUnitPrep("annotation-it-prep.xml")
442         @DbUnitExpected(value = "annotation-it-expected.xml",
443                 verify = @DbUnitVerifyTable(value = TEST_TABLE,
444                         include = {"COLUMN0", "COLUMN1"}))
445         @DbUnitTearDown(operation = DbUnitOperation.DELETE_ALL)
446         void testUpdate_throughInjectedConnection_verifiesAndCleansUp(
447                 final Connection connection) throws Exception
448         {
449             try (Statement statement = connection.createStatement())
450             {
451                 statement.execute(
452                         "UPDATE " + TEST_TABLE + " SET COLUMN1 = 'after' WHERE COLUMN0 = 'row0'");
453             }
454         }
455     }
456 
457     @ExtendWith(DbUnitExtension.class)
458     static class JdbcTesterSetupTeardownPathSample
459     {
460         @DbUnitTester
461         static IDatabaseTester databaseTester;
462 
463         @Test
464         @DbUnitPrep("annotation-it-prep.xml")
465         @DbUnitTearDown(operation = DbUnitOperation.DELETE_ALL)
466         void testPrepSeedsRow_visibleThroughInjectedConnection(final Connection connection)
467                 throws Exception
468         {
469             try (Statement statement = connection.createStatement();
470                     ResultSet resultSet = statement.executeQuery(
471                             "SELECT COUNT(*) FROM " + TEST_TABLE + " WHERE COLUMN0 = 'row0'"))
472             {
473                 resultSet.next();
474                 assertThat(resultSet.getInt(1))
475                         .as("@DbUnitPrep's CLEAN_INSERT must have seeded the row on the same"
476                                 + " connection the injected parameter hands back, before the"
477                                 + " test method body runs.")
478                         .isEqualTo(1);
479             }
480         }
481     }
482 
483     @ExtendWith(DbUnitExtension.class)
484     @DbUnitConfig(closeConnectionAfterTest = false)
485     static class CachingProviderSample
486     {
487         static final List<Connection> connectionsSeen = new ArrayList<>();
488 
489         @DbUnitTester
490         static IDatabaseTester databaseTester;
491 
492         @Test
493         @DbUnitPrep("annotation-it-prep.xml")
494         @DbUnitTearDown(operation = DbUnitOperation.DELETE_ALL)
495         void testMethodOne(final Connection connection)
496         {
497             connectionsSeen.add(connection);
498         }
499 
500         @Test
501         @DbUnitPrep("annotation-it-prep.xml")
502         @DbUnitTearDown(operation = DbUnitOperation.DELETE_ALL)
503         void testMethodTwo(final Connection connection)
504         {
505             connectionsSeen.add(connection);
506         }
507     }
508 
509     @ExtendWith(DbUnitExtension.class)
510     // closeConnectionAfterTest = false: databaseTester wraps the outer test's own connection,
511     // reused below (rowCountForPks) after this sample class finishes running.
512     @DbUnitConfig(closeConnectionAfterTest = false)
513     @DbUnitSetup(operation = DbUnitOperation.REFRESH)
514     static class ClassLevelOperationSample
515     {
516         @DbUnitTester
517         static IDatabaseTester databaseTester;
518 
519         @Test
520         @DbUnitPrep("annotation-it-pk-prep.xml")
521         void testPrepDeclaredOnMethod_classLevelSetupOperationAlsoDeclared_bothApply()
522         {
523         }
524     }
525 
526     @ExtendWith(DbUnitExtension.class)
527     // closeConnectionAfterTest = false: databaseTester wraps the outer test's own connection,
528     // reused below (rowCountForPks) after this sample class finishes running.
529     @DbUnitConfig(closeConnectionAfterTest = false)
530     @DbUnitSetup(operation = DbUnitOperation.REFRESH)
531     static class ExpectedPathClassLevelOperationSample
532     {
533         @DbUnitTester
534         static IDatabaseTester databaseTester;
535 
536         // No verifyTables/verify/verifyDefinitions: @DbUnitExpected here only needs to switch
537         // the test onto the prep/expected path, not compare any table - the row counts the
538         // calling test reads afterward are what prove the class-level @DbUnitSetup operation
539         // was applied there too, not just on the setup/teardown path.
540         @Test
541         @DbUnitPrep("annotation-it-pk-prep.xml")
542         @DbUnitExpected
543         void testPrepDeclaredOnMethod_expectedPathWithClassLevelSetupOperation_bothApply()
544         {
545         }
546     }
547 
548     @ExtendWith(DbUnitExtension.class)
549     @DbUnitConfig(databaseTesterFactory = InjectedTestCaseSample.Factory.class)
550     static class InjectedTestCaseSample
551     {
552         // resolved via getDatabaseTester()/setDatabaseTester() round-tripping, from the
553         // Factory below - see DbUnitExtension's tester/test case resolution order.
554         @DbUnitTestCase
555         static final PrepAndExpectedTestCase testCase = new DefaultPrepAndExpectedTestCase();
556 
557         @Test
558         @DbUnitPrep("annotation-it-prep.xml")
559         @DbUnitExpected(value = "annotation-it-expected.xml",
560                 verify = @DbUnitVerifyTable(value = TEST_TABLE,
561                         include = {"COLUMN0", "COLUMN1"}))
562         @DbUnitTearDown(operation = DbUnitOperation.DELETE_ALL)
563         void testWithdraw_sufficientBalance_decrementsBalance() throws Exception
564         {
565             final IDatabaseConnection connection = testCase.getDatabaseTester().getConnection();
566             try (Statement statement = connection.getConnection().createStatement())
567             {
568                 statement.execute(
569                         "UPDATE " + TEST_TABLE + " SET COLUMN1 = 'after' WHERE COLUMN0 = 'row0'");
570             }
571         }
572 
573         static class Factory implements DatabaseTesterFactory
574         {
575             @Override
576             public IDatabaseTester getDatabaseTester() throws Exception
577             {
578                 final IDatabaseTester tester = new DefaultDatabaseTester(
579                         DatabaseEnvironment.getInstance().getConnection());
580                 tester.setOperationListener(IOperationListener.NO_OP_OPERATION_LISTENER);
581                 return tester;
582             }
583         }
584     }
585 }