14

Could I somehow use AssertJ to assert a List has only one instance of a (sub)class?

public class A {}
public class B extends A {}
public class C extends A {}

@Test
public void test() {
  List<A> list = new ArrayList<A>();
  list.add(new B());

  Assertions.assertThat(list).containsOnlyOnce(B.class);
}
Maarten Dhondt
  • 577
  • 1
  • 9
  • 22

4 Answers4

23

There is a method hasOnlyElementsOfType(Class), which verifies that all elements in the Iterable have the specified type (including subclasses of the given type).

The solution could look like:

assertThat(list).hasOnlyElementsOfType(B.class).hasSize(1);
  • 1
    Welcome to Stack Overflow! While you may have solved this user's problem, code-only answers are not very helpful to users who come to this question in the future. Please edit your answer to explain why your code solves the original problem – Omore Apr 14 '17 at 20:59
  • The call to `hasSize(1)` is not needed as `hasOnlyElementsOfType` already checks this. – timomeinen Aug 16 '23 at 14:33
14

I would use AssertJ extracting feature as is:

assertThat(list).extracting("class")
                .containsOnlyOnce(B.class);
Joel Costigliola
  • 6,308
  • 27
  • 35
5

You need to define a Condition.

Following will assert that list contains only a single object reference of type B.class.

Condition condition = new Condition() {
    @Override
    public boolean matches(Object o) {
        return o.getClass() == B.class;
    }};

Assertions.assertThat(list).areExactly(1, condition);

It will fail for following cases:

list.add(new B());
list.add(new B());

and also for

B b = new B();
list.add(b);
list.add(b);

Using the Java 8 Stream API it can be achieved like

long countOfClassB = list.stream().filter(t -> t instanceof B).count();
Assertions.assertThat(countOfClassB).isEqualTo(1L);
SubOptimal
  • 22,518
  • 3
  • 53
  • 69
3

The problem with your code is that the type of list is A, but the type of the element you're trying to verify with containsOnlyOnce is Class<B>.

You need to use corresponding types. For example, you can extract the classes in the list:

Stream<Class<?>> classes = list.stream().map(x -> x.getClass());
Assertions.assertThat(classes).containsOnlyOnce(B.class);
janos
  • 120,954
  • 29
  • 226
  • 236