Assert List contains only one instance of a class using AssertJ
Asked Answered
G

4

17

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);
}
Gabor answered 13/5, 2016 at 9:10 Comment(2)
whats wrong with your current code?Gametogenesis
AssertJ's containsOnlyOnce method does not accept Class as it's argument. (unless the list was a list of Class.)Gabor
A
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);
Allfired answered 13/5, 2016 at 10:2 Comment(0)
S
25

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);
Seidler answered 14/4, 2017 at 20:56 Comment(4)
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 problemAnsate
The call to hasSize(1) is not needed as hasOnlyElementsOfType already checks this.Theomorphic
hasOnlyElementsOfType() checks only type of the items, but items can be more then one. @TheomorphicCrossroads
Thank you @MarcinGołębski, you are right. It only checks for not 0, but indeed we want to be sure it is exactly 1.Theomorphic
J
17

I would use AssertJ extracting feature as is:

assertThat(list).extracting("class")
                .containsOnlyOnce(B.class);
Juna answered 14/5, 2016 at 9:36 Comment(1)
Castigliola this is an amazing answer. Thanks for the lib.Beheld
A
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);
Allfired answered 13/5, 2016 at 10:2 Comment(0)
U
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);
Uncloak answered 13/5, 2016 at 9:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.