3

Using Mockito I'm trying to verify that certain objects are added and removed from another object. But the function that does this work stores a instance of a collection, updates the contents of this collection, and passes it to my object.

When I then try to verify that addAll and removeAll has been called with the correct objects, it seems Mockito is actually holding onto a reference to the collection, therefore has no idea what the collection contained when the methods were called. A simplified example :

class MySUT
{
    private final Collection<Object> objects = new ArrayList<>();
    public MySUT(Object firstObject)
    {
        objects.add(firstObject);
    }

    public void addNewObject(Collection<Object> other, Object newObject)
    {
        other.removeAll(objects);
        objects.clear();

        objects.add(newObject);
        other.addAll(objects);
    }
}

@Test
public void test()
{
    Object firstObject = mock(Object.class);
    Object newObject = mock(Object.class);
    Collection<Object> myObject = mock(Collection.class);

    MySUT sut = new MySUT(firstObject);

    sut.addNewObject(myObject, newObject);

    verify(myObject).removeAll(eq(Collections.singletonList(firstObject)));
    verify(myObject).addAll(eq(Collections.singletonList(newObject)));
}

This test fails claiming that the removeAll method was called with a list containing newObject which clearly it wasn't.

I can't use ArgumentCaptor either as it works the same way - so how can I verify the correct things have been passed to myObject (obviously in the real code myObject is not a simple collection)?

Jumwah
  • 517
  • 5
  • 19

1 Answers1

1

OK, I've worked it out, and thought I'd share in case anyone else has the same problem. I've made the stub return an answer, and in the answer implementation added the arugments into a new list. Then I assert against that. It's a bit nasty, but it works.

class MySUT
{
    private final Collection<Object> objects = new ArrayList<>();
    public MySUT(Object firstObject)
    {
        objects.add(firstObject);
    }

    public void addNewObject(Collection<Object> other, Object newObject)
    {
        other.removeAll(objects);
        objects.clear();

        objects.add(newObject);
        other.addAll(objects);
    }
}

@Test
public void test()
{
    Object firstObject = mock(Object.class);
    Object newObject = mock(Object.class);
    Collection<Object> myObject = mock(Collection.class);

    MySUT sut = new MySUT(firstObject);

    final List<Object> removeAllResult = new ArrayList<>();
    when(myObject.removeAll(anyCollectionOf(Object.class))).thenAnswer(new Answer<Object>()
    {
        @Override
        public Object answer(InvocationOnMock invocation) throws Throwable
        {
            removeAllResult.addAll((Collection<Object>) invocation.getArguments()[0]);
            return null;
        }
    });

    sut.addNewObject(myObject, newObject);

    verify(myObject).removeAll(anyCollectionOf(Object.class));
    verify(myObject).addAll(anyCollectionOf(Object.class));

    assertThat(removeAllResult.get(0), equalTo(firstObject));
}

If anyone else has a better/alternative solution, I'd still like to know :)

Jumwah
  • 517
  • 5
  • 19