Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asserting properties on list elements with assertJ

I have a working hamcrest assertion:

assertThat(mylist, contains(
  containsString("15"), 
  containsString("217")));

The intended behavior is:

  • mylist == asList("Abcd15", "217aB") => success
  • myList == asList("Abcd15", "218") => failure

How 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).

like image 928
CoronA Avatar asked Dec 31 '17 12:12

CoronA


People also ask

How do you compare two lists in assertEquals?

To compare two lists specifically, TestNG's Assert class has a method known as assertEquals(Object actual, Object expected) and there is an extended version of this method with customized message as assertEquals(Object actual, Object expected, String message). if the elements of the lists are in the same order.

Should I use AssertJ?

The main benefit of AssertJ is that it is set up to provide auto-completion in IDEs. Once you have specified the object you want to compare (using assertThat): the IDE will understand the type of the comparison (in this case Object) and will show you all available assertions.

How do I compare two lists in JUnit?

Using JUnit We can use the logic below to compare the equality of two lists using the assertTrue and assertFalse methods. In this first test, the size of both lists is compared before we check if the elements in both lists are the same. As both of these conditions return true, our test will pass.


1 Answers

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

like image 151
Joel Costigliola Avatar answered Sep 21 '22 12:09

Joel Costigliola