comparing two list with different type in assertj

89 Views Asked by At

I write a converter for a list and I want to test it with assertj.

List<Bar> convert(List<Foo> input)

Imagine I know how to assert that a single Foo correctly converted to a Bar. My test is something like this

@Test
void test() {
    List<Foo> input = generateInput();

    List<Bar> actual = converter.convert(input);

    // TODO asserThat input list correctly coverted to output list
}

How can I assert that each element of actual corresponds to the element in same index of input and assert that correctly converted?
I'm looking for some method like containsExactlyElementsOf that get a custom satisfier to assert that Foo correctly converted to Bar.

One way is using a for loop like this but I'm looking for a better option:

assertThat(actual).hasSameSize(input);
for(int i = 0; i < actual.size(); i++) {
    Foo foo = input.get(i);
    Bar bar = actual.get(i);
    assertThatConvertedCorrectly(foo, bar);
}
3

There are 3 best solutions below

0
mohammad aghaie On BEST ANSWER

One of my colleagues found a solution to this problem. There is an assertion zipSatisfy.
Here is the description of the function.

Verifies that the zipped pairs of actual and other elements, i.e.: (actual 1st element, other 1st element), (actual 2nd element, other 2nd element), ... all satisfy the given zipRequirements.
This assertion assumes that actual and other have the same size but they can contain different type of elements making it handy to compare objects converted to another type, for example Domain and View/DTO objects.

It does exactly what I was looking for.

1
berse2212 On

I would be interested how assertThatConvertedCorrectly is implemented. It would seem like you would need to copy-pasta the convert-Method and actually test nothing.

What you generally want to do is have little logic in your tests since more logic means you are more prone to bugs. And nobody tests their tests (lol).

Anyways the solution is to do the following:

@Test
void test() {
    List<Foo> input = generateInput();

    List<Bar> result = converter.convert(input);

    List<Bar> expectedResult = List.of(
            //create the expected Bars manually
            new Bar(expected1),
            new Bar(expected2)
    );

    assertThat(result).containsExactly(expectedResult);
}

This way you have basically no logic in your test and it's short.

2
Stefano Cordio On

Not extremely elegant but you could use satisfiesExactly and compute the requirements via Stream API:

@Test
void test() {
    List<Foo> input = generateInput();

    List<Bar> actual = converter.convert(input);

    @SuppressWarnings("unchecked")
    Consumer<Bar>[] requirements = input.stream()
      .map(foo -> (Consumer<Bar>) bar -> assertThatConvertedCorrectly(foo, bar))
      .toArray(Consumer[]::new);

    assertThat(actual).satisfiesExactly(requirements);
}

satisfiesExactly would guarantee that the proper requirement is applied to each index:

Verifies that each element satisfies the requirements corresponding to its index, so the first element must satisfy the first requirements, the second element the second requirements etc...