I am creating the tests
for two classes that share a list of data. When I use EqualsVerifier
I get an error because it is asking me for a list with data shared by these two classes.
This is the error:
Recursive datastructure. Add prefab values for one of the following types: CustomerView, List<YearConfigView>, YearConfigView
This is the @Test
class:
@Test
public void CustomerViewTest() {
EqualsVerifier.forClass(CustomerView.class).withRedefinedSuperclass().withGenericPrefabValues(CustomerView.class).verify();
}
@Test
public void YearConfigViewTest() {
EqualsVerifier.forClass(YearConfigView.class).suppress(Warning.ALL_FIELDS_SHOULD_BE_USED).verify();
}
CustomerView.java
:
public class CustomerView extends EntityBase<Integer> {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private List<YearConfigView> yearConfigs;
@JsonProperty("current_year_config")
public YearConfigView getCurrentYearConfig() {
if (this.getYearConfigs() == null || this.getYearConfigs().isEmpty()) {
return null;
}
int currentYear = LocalDate.now().getYear();
return this.yearConfigs.parallelStream().filter(yc -> yc.getYear() == currentYear).findAny().orElse(null);
}
}
YearConfigView.java
:
public class YearConfigView extends EntityBase<Integer> {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private CustomerView customer;
private Integer year;
private String comments;
}
My problem: What do I have to change or add in EqualsVerifier
to solve the problem?
Creator of EqualsVerifier here.
Without seeing your classes (I'd like to see exactly which fields CustomerView
and YearConfigView
have, and how equals
and hashCode
are implemented on both classes), it's hard to say for certain what's going on, but I suspect it's this:
CustomerView
has a reference toYearConfigView
(or perhapsList<YearConfigView>
), andYearConfigView
has a reference toCustomerView
.
EqualsVerifier, while doing its thing, tries to make instances of the classes it's verifying, and giving its fields proper values too. In order to do that, it must recursively instantiate the class's fields and give those values too. Usually, that's not a problem, but sometimes you run into a loop, like in your case: in order to create a value for CustomerView
, it must have a value for YearConfigView
and vice versa.
The way to avoid this, is by giving EqualsVerifier some 'prefab values'. I see you've already tried to do something like this, by adding .withGenericPrefabValues(CustomerView.class)
. (This method requires 2 parameters so I suspect you may have removed some code before posting it to StackOverflow 😉) This only works if CustomerView
is itself a generic class, which I can't verify because you didn't post that particular piece of code. In any event, you shouldn't give generic prefab values or regular prefab values for the class you're testing.
In general, though, your tests should both give a prefab value for the other class. That would look like this:
@Test
public void CustomerViewTest() {
YearConfigView one = new YearConfigView();
one.setYear(2020);
YearConfigView two = new YearConfigView();
two.setYear(2021);
EqualsVerifier.forClass(CustomerView.class)
.withRedefinedSuperclass()
.withPrefabValues(YearConfigView.class, one, two)
.verify();
}
@Test
public void YearConfigViewTest() {
CustomerView one = new CustomerView();
one.setName("Alice");
CustomerView two = new CustomerView();
two.setName("Bob");
EqualsVerifier.forClass(YearConfigView.class)
.suppress(Warning.ALL_FIELDS_SHOULD_BE_USED)
.withPrefabValues(CustomerView.class, one, two)
.verify();
}
Note that I still don't know which fields are included in your equals
methods, so I'm only making an educated guess about how to instantiate your classes.
For more information, see the relevant page in the EqualsVerifier documentation. Since the classes are JPA entities, this page might also be helpful: it explains how the @Id
is treated by EqualsVerifier.