Allow logical operations on assertions
nakulj opened this issue · 4 comments
It would be nice if there was some way of performing logical operations on assertions, whether fluently or not.
// fluent version
assertThat(foo).isEqualTo(3).orThat(bar).isEqualTo(5);
assertAtLeastOneOf(
that(foo).isEqualTo(3),
that(bar).isEqualTo(4)
);
The fluent version would be a very big API change to pretty much every Subject. It couldn't work as you propose, because isEqualTo(3)
has to throw an exception for non-3 subjects. I don't expect we would make a change like that anytime soon.
I see no huge technical barriers to implementing assertAtLeastOneOf
, but it doesn't seem like a hugely important feature to have. A disjunction like this would tend to be useful only in tests that are already complicated enough to merit some concern (since tests should be simple). And in the worst case, you can emulate this behavior with an assertion on ordinary booleans.
I likewise don't expect us to add this. One minor reason for that is that the "failure path" for assertions can be pretty slow, like when it constructs very long failure messages. If we wanted to support logical operations "properly," we'd design an API that allowed deferring that work until later.
That said, it should be possible to implement this as an external extension if you want: You'd have to implement a custom FailureStrategy that collected failures from the sub-assertions, along with a bunch of custom that(...) methods that counted how many assertions had been performed (so that you can compare that to the number of failures). Then you'd expose some kind of API to the multiple assertions, likely either having the user implement a lambda or write a try-with-resources block. [edit: This turns out not to work in the general case; see below.]
One additional downside that that will expose is that the only way to fail with full information will be to dump the whole list of failure messages, which may be quite long.
The alternative way to do this would be for us to implement "Fuzzy Truth for single objects." I forget whether we have an external feature request open about that yet. But it would address any concerns around performance or failure messaging.
a bunch of custom that(...) methods that counted how many assertions had been performed (so that you can compare that to the number of failures)
That assumes that callers perform a single assertion per that(...)
call. That's almost always going to be a reasonable assumption: Few users are going to write...
StringSubject a = holds.that(myString);
a.startsWith("http:");
a.startsWith("https:");
...when they could just write...
holds.that(myString).startsWith("http:");
holds.that(myString).startsWith("https:");
But we could imagine seeing multiple assertions on the same Subject
instance in the case of Kotlin users, as discussed in #572.
Fuzzy Truth for single objects.
I think this is actually what I really wanted :)
I understand that failure messaging for fuzzy truth is hard- but it would be nice for it to be handled once, at the library level, rather than multiple times by everyone who writes a fuzzy test.