Reputation: 1274
I have two classes:
class Outer {
Inner inner = new Inner("value");
}
class Inner {
private final String value;
Inner(String value) {
this.value = value;
}
}
public Optional<Outer> getOptionalValue() {
return Optional.of(new Outer());
}
And my test:
public void testCLass() {
Assertions.assertThat(getOptionalValue())
.isPresent()
.map(v -> v.inner.value)
.isEqualTo("value");
}
I expect it to pass, because isPresent
unwraps optional, map
converts Outer
into value
and in the last method I just compare strings.
But it fails on the last line with the message:
Expecting:
<Optional[value]>
to be equal to:
<"value">
but was not.
I have no idea why the optional is not unwrapped
Upvotes: 27
Views: 24007
Reputation: 3531
The javadoc for OptionalAssert
's map method states
Call
map
on theOptional
under test, assertions chained afterwards are performed on theOptional
resulting from themap
call.
However, isEqualTo
is actually comparing the value of the AbstractAssert
as a whole. It's not overriden for OptionalAssert
to compare the enclosed value. An OptionalAssert
's value, the Optional
itself, is not equal to a String
.
You'll want to use hasValue
Verifies that the actual
Optional
contains the given value (alias ofcontains(Object)
).Assertion will pass :
assertThat(Optional.of("something")).hasValue("something"); assertThat(Optional.of(10)).contains(10);
So
Assertions.assertThat(getOptionalValue())
.isPresent()
.map(v -> v.inner.value)
.hasValue("value");
Or, because hasValue
actually performs the isPresent
check internally, you could just use
Assertions.assertThat(getOptionalValue())
.map(v -> v.inner.value)
.hasValue("value");
Upvotes: 53
Reputation: 86223
If you can, make the test directly on the received Optional
rather than taking it apart and testing three levels deep.
Assertions.assertThat(getOptionalValue()).hasValue(new Outer());
It’s clear and simple, it’s the recommended way, and if Outer
and Inner
have appropriate equals
methods, you need nothing more. While I haven’t tried it with AssertJ myself, I believe that it gives clear messages both in the case where the Optional
is empty and in the case where it holds an incorrect value at some level.
Upvotes: 2
Reputation: 59950
You are missing a step, you should to use get()
to get the value of the Optional, because map in your case, returns an Optional<String>
and not a String:
.map(v -> v.inner.getValue())
.get()
.isEqualTo("value");
Or if you want to stick with the Optional
, you should to compare with an Optional
:
.map(v -> v.inner.getValue())
.isEqualTo(Optional.of("value"));
Upvotes: 4