1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
30 import org.dbunit.DatabaseEnvironment;
31 import org.dbunit.DatabaseProfile;
32 import org.dbunit.IDatabaseTester;
33 import org.dbunit.JdbcDatabaseTester;
34 import org.dbunit.annotation.DbUnitExpected;
35 import org.dbunit.annotation.DbUnitPrep;
36 import org.dbunit.annotation.DbUnitRowCountCheck;
37 import org.dbunit.annotation.DbUnitSetup;
38 import org.dbunit.annotation.DbUnitTearDown;
39 import org.dbunit.annotation.DbUnitTester;
40 import org.dbunit.annotation.DbUnitVerifyTable;
41 import org.dbunit.database.IDatabaseConnection;
42 import org.dbunit.database.rowcount.ClearRowCountCheckSystemProperties;
43 import org.dbunit.database.rowcount.UnexpectedRowCountException;
44 import org.dbunit.operation.DbUnitOperation;
45 import org.junit.jupiter.api.Test;
46 import org.junit.jupiter.api.extension.ExtendWith;
47 import org.junit.platform.engine.TestExecutionResult;
48 import org.junit.platform.testkit.engine.EngineTestKit;
49 import org.junit.platform.testkit.engine.Event;
50
51
52
53
54
55
56
57
58
59
60
61
62 @ClearRowCountCheckSystemProperties
63 class DbUnitExtensionRealTesterRowCountCheckIT
64 {
65 private static final String TEST_TABLE = "TEST_TABLE";
66 private static final String EMPTY_TABLE = "EMPTY_TABLE";
67
68 @Test
69 void testAfterTestExecution_setupTeardownPathWithRowCountCheck_piggybacksBaselineAndVerifiesClean()
70 throws Exception
71 {
72 final DatabaseEnvironment environment = DatabaseEnvironment.getInstance();
73 runSampleExpectingSuccess(environment, SetupTeardownPathSample.class);
74
75 final IDatabaseConnection verifyConnection = environment.getConnection();
76 assertThat(rowCount(verifyConnection, TEST_TABLE))
77 .as("The setup/teardown path with @DbUnitRowCountCheck, driven through a real"
78 + " JdbcDatabaseTester: baseline piggybacks on onSetup()'s connection,"
79 + " verify re-uses that memoized connection, and"
80 + " @DbUnitTearDown(DELETE_ALL) commits - a separate connection sees"
81 + " TEST_TABLE empty.")
82 .isZero();
83 }
84
85 @Test
86 void testAfterTestExecution_prepExpectedPathWithRowCountCheck_verifiesDataAndRowCountsClean()
87 throws Exception
88 {
89 final DatabaseEnvironment environment = DatabaseEnvironment.getInstance();
90 runSampleExpectingSuccess(environment, PrepExpectedPathSample.class);
91
92 final IDatabaseConnection verifyConnection = environment.getConnection();
93 assertThat(rowCount(verifyConnection, TEST_TABLE))
94 .as("The prep/expected path with @DbUnitRowCountCheck, driven through a real"
95 + " JdbcDatabaseTester: DefaultPrepAndExpectedTestCase captures the"
96 + " baseline and verifies data + row counts on its reusable connection,"
97 + " and @DbUnitTearDown(DELETE_ALL) commits.")
98 .isZero();
99 }
100
101 @Test
102 void testAfterTestExecution_rowLeakedThroughARealTester_failsProvingTheCheckActuallyRan()
103 throws Exception
104 {
105 final DatabaseEnvironment environment = DatabaseEnvironment.getInstance();
106 try
107 {
108 LeakThroughRealTesterSample.databaseTester = newJdbcDatabaseTester(environment);
109
110 final Event failed = EngineTestKit.engine("junit-jupiter")
111 .selectors(selectClass(LeakThroughRealTesterSample.class)).execute()
112 .testEvents().failed().stream().findFirst().orElseThrow(
113 () -> new AssertionError("Expected one failed test event."));
114 final Throwable reported = failed.getRequiredPayload(TestExecutionResult.class)
115 .getThrowable().orElseThrow(
116 () -> new AssertionError("Expected a reported throwable."));
117
118 assertThat(reported)
119 .as("A row left in an unlisted table must fail with"
120 + " UnexpectedRowCountException even when the tester is a real"
121 + " fresh-connection JdbcDatabaseTester - proving the check is"
122 + " genuinely running, not silently no-op because a fresh"
123 + " connection defeated the baseline.")
124 .isInstanceOf(UnexpectedRowCountException.class);
125 } finally
126 {
127 deleteAllRowsQuietly(environment, EMPTY_TABLE);
128 environment.closeConnection();
129 }
130 }
131
132 private void runSampleExpectingSuccess(final DatabaseEnvironment environment,
133 final Class<?> sampleClass) throws Exception
134 {
135 try
136 {
137 setSampleTester(sampleClass, newJdbcDatabaseTester(environment));
138
139 EngineTestKit.engine("junit-jupiter").selectors(selectClass(sampleClass)).execute()
140 .testEvents().assertStatistics(stats -> stats.started(1).succeeded(1));
141 } finally
142 {
143 deleteAllRowsQuietly(environment, TEST_TABLE);
144 environment.closeConnection();
145 }
146 }
147
148 private void setSampleTester(final Class<?> sampleClass, final IDatabaseTester tester)
149 {
150 if (sampleClass == SetupTeardownPathSample.class)
151 {
152 SetupTeardownPathSample.databaseTester = tester;
153 } else
154 {
155 PrepExpectedPathSample.databaseTester = tester;
156 }
157 }
158
159 private static IDatabaseTester newJdbcDatabaseTester(final DatabaseEnvironment environment)
160 throws Exception
161 {
162 final DatabaseProfile profile = environment.getProfile();
163 return new JdbcDatabaseTester(profile.getDriverClass(), profile.getConnectionUrl(),
164 profile.getUser(), profile.getPassword(), profile.getSchema());
165 }
166
167 private static int rowCount(final IDatabaseConnection connection, final String tableName)
168 throws Exception
169 {
170 try (Statement statement = connection.getConnection().createStatement();
171 ResultSet resultSet =
172 statement.executeQuery("SELECT COUNT(*) FROM " + tableName))
173 {
174 resultSet.next();
175 return resultSet.getInt(1);
176 }
177 }
178
179 private static void deleteAllRowsQuietly(final DatabaseEnvironment environment,
180 final String tableName)
181 {
182 try (Statement statement =
183 environment.getConnection().getConnection().createStatement())
184 {
185 statement.execute("DELETE FROM " + tableName);
186 } catch (final Exception e)
187 {
188
189 }
190 }
191
192 @ExtendWith(DbUnitExtension.class)
193 @ClearRowCountCheckSystemProperties
194 @DbUnitRowCountCheck
195 static class SetupTeardownPathSample
196 {
197 @DbUnitTester
198 static IDatabaseTester databaseTester;
199
200 @Test
201 @DbUnitPrep("annotation-it-prep.xml")
202 @DbUnitTearDown(operation = DbUnitOperation.DELETE_ALL)
203 void mutateTheSeededRow(final Connection connection) throws Exception
204 {
205 try (Statement statement = connection.createStatement())
206 {
207 statement.execute("UPDATE " + TEST_TABLE
208 + " SET COLUMN1 = 'after' WHERE COLUMN0 = 'row0'");
209 }
210 }
211 }
212
213 @ExtendWith(DbUnitExtension.class)
214 @ClearRowCountCheckSystemProperties
215 @DbUnitRowCountCheck
216 static class PrepExpectedPathSample
217 {
218 @DbUnitTester
219 static IDatabaseTester databaseTester;
220
221 @Test
222 @DbUnitPrep("annotation-it-prep.xml")
223 @DbUnitExpected(value = "annotation-it-expected.xml",
224 verify = @DbUnitVerifyTable(value = TEST_TABLE,
225 include = {"COLUMN0", "COLUMN1"}))
226 @DbUnitTearDown(operation = DbUnitOperation.DELETE_ALL)
227 void mutateTheSeededRow(final Connection connection) throws Exception
228 {
229 try (Statement statement = connection.createStatement())
230 {
231 statement.execute("UPDATE " + TEST_TABLE
232 + " SET COLUMN1 = 'after' WHERE COLUMN0 = 'row0'");
233 }
234 }
235 }
236
237 @ExtendWith(DbUnitExtension.class)
238 @ClearRowCountCheckSystemProperties
239 @DbUnitRowCountCheck
240 @DbUnitSetup(operation = DbUnitOperation.NONE)
241 static class LeakThroughRealTesterSample
242 {
243 @DbUnitTester
244 static IDatabaseTester databaseTester;
245
246 @Test
247 void leaveARowInAnUnlistedTable(final Connection connection) throws Exception
248 {
249 try (Statement statement = connection.createStatement())
250 {
251 statement.execute("INSERT INTO " + EMPTY_TABLE + " (COLUMN0) VALUES ('leaked')");
252 }
253 }
254 }
255 }