You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Custom Hamcrest matchers are incredibly powerful. Any non-trivial POJO will require checking multiple values, and even if they're bundled into a single method they're still a bit noisy (IMO).
This is something that's probably outside of the scope of the official modules - but so broadly useful that it might be a useful sister project. The official modules probably won't require any changes other than, at most, something like changing private to protected in a few places.
Using a traditional custom Hamcrest matcher we would write
There's no problem adding this to local extensions.
Adding this to the official modules is probbaly code bloat - it can be used to verify that your container initialization was successful but it will be mostly used in regular tests. It also opens the door to people who want to "add just one more thing" to the API.
That said some matcher needs are so common that they should be implemented once and reused. This should be documented in an easy to find location, and the matchers may be able to take advantage of knowing that they're connected to a Container.
Next steps
I'm going to revisit the Hamcrest project. When I developed this approach they didn't have the matcher I needed and I took advantage of the Container API when writing my matcher. The latter isn't a strict requirement though - at most it means the constructor will require additional parameters.
I'll also put together sample code where I extend a standard module so it adds the noun.verb() methods.
Finally I'll keep my eyes open in case I see places where a minor addition to the API, perhaps nothing more than changing something from private to protected, can make a big difference in these implementations.
Sample code
Most of the matcher is glue required by TypeSafeMatcher<T>. The actual test is handled by a single method:
// note: not all JdbcDatabaseContainers implement getConnection()!@OverridepublicbooleanmatchesSafely(JdbcDatabaseContainerserver) {
booleanfound = false;
try (Connectionconn = server.getConnection()) {
finalDatabaseMetaDatamd = conn.getMetaData();
// strip quotesfinalStringschemaPattern = schemaName.matches("(\"|'|`).*(\"|'|`)") ?
schemaName.substring(1, schemaName.length() - 1) : schemaName;
finalStringtablePattern = tableName.matches("(\"|'|`).*(\"|'|`)") ?
tableName.substring(1, tableName.length() - 1) : tableName;
// look for matching entry// note: we should check metadata to see if "schema" actually goes// into "schema" or "category"try (ResultSetrs = md.getTables(catalogName, schemaPattern, tablePattern, null)) {
found = rs.next();
}
} catch (SQLExceptione) {
thrownewAssertionFailedError("Unable to check metadata: " + e.getMessage());
}
returnfound;
}
(This has worked for me but I should check the database's metadata to see whether the catalog, schema, and table names should be quoted, what character to use, etc. A database-specific module can use hardcoded values but a generic matcher should call Connection#getDatabaseMetaData() and ideally it would only be called once, not per matcher execution. This is a place where it may make sense to extend JdbcDatabaseContainer to it provides cached (but limited) metadata information.)
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Custom Hamcrest matchers are incredibly powerful. Any non-trivial POJO will require checking multiple values, and even if they're bundled into a single method they're still a bit noisy (IMO).
This is something that's probably outside of the scope of the official modules - but so broadly useful that it might be a useful sister project. The official modules probably won't require any changes other than, at most, something like changing
private
toprotected
in a few places.Using a traditional custom Hamcrest matcher we would write
but in my view this is unnecessary clutter. I would be much cleaner to use:
This is easy to implement in a local extension.
Potential drawbacks
There's no problem adding this to local extensions.
Adding this to the official modules is probbaly code bloat - it can be used to verify that your container initialization was successful but it will be mostly used in regular tests. It also opens the door to people who want to "add just one more thing" to the API.
That said some matcher needs are so common that they should be implemented once and reused. This should be documented in an easy to find location, and the matchers may be able to take advantage of knowing that they're connected to a Container.
Next steps
I'm going to revisit the Hamcrest project. When I developed this approach they didn't have the matcher I needed and I took advantage of the Container API when writing my matcher. The latter isn't a strict requirement though - at most it means the constructor will require additional parameters.
I'll also put together sample code where I extend a standard module so it adds the
noun.verb()
methods.Finally I'll keep my eyes open in case I see places where a minor addition to the API, perhaps nothing more than changing something from
private
toprotected
, can make a big difference in these implementations.Sample code
Most of the matcher is glue required by
TypeSafeMatcher<T>
. The actual test is handled by a single method:(This has worked for me but I should check the database's metadata to see whether the catalog, schema, and table names should be quoted, what character to use, etc. A database-specific module can use hardcoded values but a generic matcher should call
Connection#getDatabaseMetaData()
and ideally it would only be called once, not per matcher execution. This is a place where it may make sense to extendJdbcDatabaseContainer
to it provides cached (but limited) metadata information.)Beta Was this translation helpful? Give feedback.
All reactions