Asserting that collection contains single matching item and then making further assertions on that item

31 Views Asked by At

The test below employs the strikt framework to first assert that the list contains a single pair satisfying first=="B" and then make an assertion on second of that pair.

@Test
fun `should verify that key occurs once and has expected value`() {
    val listOfPairs = listOf("A" to 1, "B" to 2, "C" to 3, "C" to 3)
    expectThat(listOfPairs).one { get { this.first }.isEqualTo("B") }
    expectThat(listOfPairs).filter { it.first.equals("B") }.single().get { this.second }.isEqualTo(2)
}

Is there a way to fluently continue the first expectThat to include the second assertion? I'm aware that it is debatable whether this is actually desirable, but what I really don't fancy is that to access the pair again in the second expectThat, I need to use a predicate instead of an assertion.

2

There are 2 best solutions below

0
Simon Jacobs On

Given the return value of one doesn't expose any useful properties or methods, I think realistically you are looking at a custom assertion.

This should fit the bill:

fun Assertion.Builder<List<Pair<String, Int>>>.hasKeyOnceWithValue(key: String, value: Int): Assertion.Builder<List<Pair<String, Int>>> {
    return assert("Has key $key once in the list with value $value") { actual ->
        actual.singleOrNull { pair -> pair.first == key }
            ?.let { singlePair ->
                if(singlePair.second == value)
                    pass()
                else
                    fail(actual = actual, description = "Key was present but had value ${singlePair.second}")
            }
            ?: fail(actual = actual, description = "Key was not present")
    }
}

And sample tests:

@Test
fun passes() {
    expectThat(listOf("a" to 1)).hasKeyOnceWithValue("a", 1)
}

@Test
fun failsAsDoesNotHaveKey() {
    expectThat(listOf("b" to 1)).hasKeyOnceWithValue("a", 1)
}

@Test
fun failsAsHasKeyButNotValue() {
    expectThat(listOf("a" to 2)).hasKeyOnceWithValue("a", 1)
}
0
Martin Zeitler On

It's rather pointless to nest assertions; better chain them (as the documentation suggests):

expectThat(listOfPairs)
    .one { get { this.first }.isEqualTo("B") }
    .filter { it.first.equals("B") }.single().get { this.second }.isEqualTo(2)