The project uses TestNg, Java11, Spring test
I am writing testNG tests for API I have a java object that has this kind of stucture:
class Object1
private Object2 o2;
private List<Object3> o3;
Where Object2
is not only composed of primitive attributes.
I would like to test if 2 Object1
are equals with these rules:
o2
is null, don't fail even if the other o2
is noto3
is null or empty, don't fail even if the other o3
is noto3
is not null nor empty, compare only non null Object3
fieldsTo sum up, I would like to assert that 2 objects are the same, ignoring null fields recursively.
I could do it
assertThat(actual).usingRecursiveComparison().ignoringActualNullFields().isEqualTo(other);
but the recursive null fields are not ignored.
How can I fix this?
I finally created my own asserts like this:
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.Assertions;
import java.util.List;
import java.util.stream.Collectors;
public class Object1Assert extends AbstractAssert<Object1Assert, Object1> {
public Object1Assert isEqualTo(Object1 other) {
// specially for null
if(actual == other) {return this;}
if(actual.getObject2() != null) {
Assertions.assertThat(other.getObject2()).isEqualToIgnoringNullFields(actual.getObject2());
}
if(actual.getObject3() != null) {
for(Object3 object3 : actual.getObject3()) {
my.package.Assertions.assertThat(object3).isIn(other.getObject3());
}
}
// return the current assertion for method chaining
return this;
}
public Object1Assert(Object1 actual) {
super(actual, Object1Assert.class);
}
public static Object1Assert assertThat(Object1 actual) {
return new Object1Assert(actual);
}
}
public class Assertions {
public static Object3Assert assertThat(Object3 actual) {
return new Object3Assert(actual);
}
}
public class Object3Assert extends AbstractAssert<Object3Assert, Object3> {
public Object3Assert isIn(List<Object3> others) {
List<String> otherStringIds = others.stream().map(Object3::getStringId).collect(Collectors.toList());
Assertions.assertThat(otherStringIds).isNotEmpty();
Assertions.assertThat(actual.getStringId()).isIn(otherStringIds);
for (Object3 otherObject3 : others) {
if(actual.getStringId().equalsIgnoreCase(otherObject3.getStringId())) {
Assertions.assertThat(otherObject3).usingComparatorForType(Comparators.bigDecimalComparator, BigDecimal.class).isEqualToIgnoringNullFields(actual);
}
}
// return the current assertion for method chaining
return this;
}
public Object3Assert(Object3 actual) {
super(actual, Object3Assert.class);
}
public static Object3Assert assertThat(Object3 actual) {
return new Object3Assert(actual);
}
}
I created this class for each type I needed with this tutorial https://www.baeldung.com/assertj-custom-assertion