I have a working hamcrest assertion:
assertThat(mylist, contains(
containsString("15"),
containsString("217")));
The intended behavior is:
mylist == asList("Abcd15", "217aB")
=> successmyList == asList("Abcd15", "218")
=> failureHow can I migrate this expression to assertJ. Of course there exist naive solutions, like asserting on the first and second value, like this:
assertThat(mylist.get(0)).contains("15");
assertThat(mylist.get(1)).contains("217");
But these are assertions on the list elements, not on the list. Trying asserts on the list restricts me to very generic functions. So maybe it could be only resolved with a custom assertion, something like the following would be fine:
assertThat(mylist).elements()
.next().contains("15")
.next().contains("217")
But before I write a custom assert, I would be interested in how others would solve this problem?
Edit: One additional non-functional requirement is, that the test should be easily extendible by additional contstraints. In Hamcrest it is quite easy to express additional constraints, e.g.
assertThat(mylist, contains(
emptyString(), //additional element
allOf(containsString("08"), containsString("15")), //extended constraint
containsString("217"))); // unchanged
Tests being dependent on the list index will have to be renumbered for this example, Tests using a custom condition will have to rewrite the complete condition (note that the constraints in allOf
are not restricted to substring checks).
For this kind of assertions Hamcrest is superior to AssertJ, you can mimic Hamcrest with Conditions but you need to write them as there are none provided out of the box in AssertJ (assertJ philosphy is not to compete with Hamcrest on this aspect).
In the next AssertJ version (soon to be released!), you will be able to reuse Hamcrest Matcher to build AssertJ conditions, example:
Condition<String> containing123 = new HamcrestCondition<>(containsString("123"));
// assertions succeed
assertThat("abc123").is(containing123);
assertThat("def456").isNot(containing123);
As a final note, this suggestion ...
assertThat(mylist).elements()
.next().contains("15")
.next().contains("217")
... unfortunately can't work because of generics limitation, although you know that you have a List of String, Java generics are not powerful enough to choose a specific type (StringAssert
) depending on another (String
), this means you can only perform Object
assertion on the elements but not String
assertion.
-- edit --
Since 3.13.0 one can use asInstanceOf
to get specific type assertions, this is useful if the declared type is Object but the runtime type is more specific.
Example:
// Given a String declared as an Object
Object value = "Once upon a time in the west";
// With asInstanceOf, we switch to specific String assertion by specifying the InstanceOfAssertFactory for String
assertThat(value).asInstanceOf(InstanceOfAssertFactories.STRING)
.startsWith("Once");`
see https://assertj.github.io/doc/#assertj-core-3.13.0-asInstanceOf