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