'Assert two List have same subtypes in a certain order

I would like to check if two lists (let's say, ArrayLists) have exactly the same instance classes, based in an expected List. To do so, I have built the next method, but I was wondering whether there is another fancy way using certain library, like assertJ.

    private void assertConcreteTypes(List actual, List expected) {
        for (int i = 0; i < actual.size(); i++){
            assertThat(actual.get(i)).isExactlyInstanceOf(expected.get(i).getClass());
        }
    }

Any suggestion would be more than welcome. Thanks!



Solution 1:[1]

You can create a custom Assertj asserter and you can leverage it for asserting types.

class TypeAssert extends AbstractAssert<TypeAssert, List<?>> {

    public TypeAssert(List<?> actual) {
        super(actual, TypeAssert.class);
    }

    public TypeAssert hasElementsOfExactlyTheSameTypeAs(List<?> expected) {
        isNotNull();
        for (int i = 0; i < actual.size(); i++) {
            if (!actual.get(i).getClass().equals(expected.get(i).getClass())) {
                failWithMessage("Expected [%s]th element to be of type: %s but was of type: %s",
                    i, expected.get(i).getClass(), actual.get(i).getClass());
            }
        }

        return this;
    }
}

You'll need a static method that will expose the object of our Custom Exporter.

class Assertions {

    // static factory method which exposes custom asserted
    static TypeAssert assertThat(List<?> actual) {
        return new TypeAssert(actual);
    }
}

And then you can use the above method for asserting based on type.

List<Object> actual = List.of(new Employee());
List<Object> expected = List.of(new StringBuilder());

Assertions.assertThat(actual).hasElementsOfExactlyTheSameTypeAs(expected);

If you are asserting based on type only at 1 or 2 places then I fill the approach you have mentioned is much cleaner and readable. But if you need to such assertion at several places then I fill you should create a custom Asserter.

Solution 2:[2]

You need to take into account lists of different sizes as well as null elements in the lists.

This seems quite readable and caters to these edge cases:

private void assertConcreteTypes(List actual, List expected) {
    assertEquals(classes(expected), classes(actual));
}

private List<Class<?>> classes(List<Object> list) {
    return list.stream().map(v -> v == null ? null : v.getClass()).collect(Collectors.toList());
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2