23

I need to verify a method with multiple parameter in Mockito, but need to capture only one argument, the others I need only a simple matcher. Is that possible?

For instance, if I have:

@Mock
private Map<K,V> mockedMap;
...
ArgumentCaptor<K> argument = ArgumentCaptor.forClass(K.class);
verify(mockedMap).put(argument.capture(), any(V.class));

In this case do I need to write a captor for each argument in spite of the fact I need to capture only the first argument?

durron597
  • 31,968
  • 17
  • 99
  • 158
kavai77
  • 6,282
  • 7
  • 33
  • 48

2 Answers2

49

In this case do I need to write a captor for each argument in spite of the fact I need to capture only the first argument?

durron597's answer is correct—you do not need to capture all arguments if you want to capture one of them. One point of clarification, though: a call to ArgumentCaptor.capture() counts as a Mockito matcher, and in Mockito if you use a matcher for any method argument you do have to use a matcher for all arguments.

For a method yourMock.yourMethod(int, int, int) and an ArgumentCaptor<Integer> intCaptor:

/*  good: */  verify(yourMock).yourMethod(2, 3, 4);  // eq by default
/*  same: */  verify(yourMock).yourMethod(eq(2), eq(3), eq(4));

/*   BAD: */  verify(yourMock).yourMethod(intCaptor.capture(), 3, 4);
/* fixed: */  verify(yourMock).yourMethod(intCaptor.capture(), eq(3), eq(4));

These also work:

verify(yourMock).yourMethod(intCaptor.capture(), eq(5), otherIntCaptor.capture());
verify(yourMock).yourMethod(intCaptor.capture(), anyInt(), gt(9000));
Community
  • 1
  • 1
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
6

Of course it works. Why wouldn't it?

import java.util.Map;

import org.junit.*;
import org.mockito.*;

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

public class MockitoTest {
  @Mock
  private Map<Integer, String> mockedMap;

  @Before
  public void setup() {
    MockitoAnnotations.initMocks(this);
  }

  @Test
  public void testCaptor() {
    mockedMap.put(5, "Hello World!");
    ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
    verify(mockedMap).put(argument.capture(), any(String.class));

    assertEquals(5L, argument.getValue().longValue());
  }
}

This works correctly and passes.


As an aside, you almost never want to mock data structures such as List and Map, because it's a giant pain to correctly mock all their behavior and most code won't be very happy if you, for example, add an element and then the element doesn't actually exist. In your case, it would probably be better to create a partial mock (using Mockito.spy) than an actual mock.

durron597
  • 31,968
  • 17
  • 99
  • 158