我可以混合 Argument Captor 和常规匹配器吗?

2022-09-02 19:46:59

我需要在Mockito中验证具有多个参数的方法,但只需要捕获一个参数,其他参数我只需要一个简单的匹配器。这可能吗?

例如,如果我有:

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

在这种情况下,我是否需要为每个参数编写一个捕获器,尽管我只需要捕获第一个参数?


答案 1

在这种情况下,我是否需要为每个参数编写一个捕获器,尽管我只需要捕获第一个参数?

durron597 的答案是正确的 — 如果你想捕获其中一个参数,则无需捕获所有参数。不过,有一点需要澄清:对 Mockito 匹配器的调用算作 Mockito 匹配器,在 Mockito 中,如果您对任何方法参数使用匹配器,则必须对所有参数使用匹配器ArgumentCaptor.capture()

对于方法和 :yourMock.yourMethod(int, int, int)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));

这些也适用于:

verify(yourMock).yourMethod(intCaptor.capture(), eq(5), otherIntCaptor.capture());
verify(yourMock).yourMethod(intCaptor.capture(), anyInt(), gt(9000));

答案 2

当然,它有效。为什么不呢?

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());
  }
}

这工作正常并通过。


顺便说一句,你几乎从来不想模拟像和这样的数据结构,因为正确模拟它们的所有行为是一个巨大的痛苦,如果你,例如,添加一个元素,然后元素实际上并不存在,大多数代码都不会很高兴。在你的例子中,创建一个部分模拟(使用Mockito.spy)可能比创建一个实际的模拟更好。ListMap


推荐