3

In Junit5 i used the following snippet often to test if a collection contains elements that fullfill certain criteria:

assertThat("The list of addresses", addresses.getAddressReferences(), containsInAnyOrder(
        allOf(
            hasProperty("id", is("abc")),
            hasProperty("role", is(SENDER))
        ),
        allOf(
            hasProperty("id", is("def")),
            hasProperty("role", is(RECEIVER))
        )
    ));

I did not yet find a way to express this in kotest I tried shouldContainExactlyInAnyOrder and such but they expect an actual object. I don't know how to express that i want to test each element against a different matcher.

I also checked the inspectors which might be the solution but they only seem to help to make assertions on ALL elements in the list at once.

Chris
  • 7,675
  • 8
  • 51
  • 101

2 Answers2

5

Kotest Inspectors might be what you are looking for. They allow to test that all, none, or a specific number of elements in a collection satisfy specific assertions.

Without knowledge of the address references data types I would assume that your example can be translated to Kotest like this:

withClue("The list of addresses") {
    val references = addresses.getAddressReferences()
    assertSoftly {
        references shouldHaveSize 2
        references.forOne {
            it.id shouldBe "abc"
            it.role shouldBe SENDER
        }
        references.forOne {
            it.id shouldBe "def"
            it.role shouldBe RECEIVER
        }
    }
}

As pointed out by @LeoColman, the withClue and assertSoftly are not mandatory:

  • withClue just adds the given clue as additional info to the assertion error message in case an assertion fails.
  • assertSoftly lets all of the assertions inside it run instead of stopping at the first failed assertion. This means that if we have for instance a collection of 3 elements, we still get information about the fact that there is or is not an element with id "abc" and role SENDER.
Karsten Gabriel
  • 3,115
  • 6
  • 19
  • 1
    This gives _nearly_ as good a result as JUnit5+Hamcrest. The latter would say something like "property id should be abc but is xyz" whereas Kotest would say "xyz should be abc". It can be fixed by adding nested withClue calls around every `it.property shouldBe`, but that would make the code a bit bloated. – Klitos Kyriacou Aug 17 '22 at 13:20
  • 1
    Thanks for the answers i really like the solution especially that i do not need property names as strings anymore. – Chris Aug 17 '22 at 18:06
1

Using inspectors as suggested by @Karsten seems like the way here!

I present a simpler way to make the same assertions if you want to keep the code smaller:

val references = addresses.getAddressReferences()
references.forOne {
    it.id shouldBe "abc"
    it.role shouldBe SENDER
}

references.forOne {
    it.id shouldBe "def"
    it.role shouldBe RECEIVER
}

Both withClue and assertSoftly are optional

LeoColman
  • 6,950
  • 7
  • 34
  • 63