java - 如何在 Java 中匹配对象数组的 Map

标签 java mockito

如何在 Mockito 中匹配 Object[]Map?我用过

  String[] entity= {"entity1"}
  Map<String,Object[]> queryParam = new HashMap<String,Object[]>();
  queryParam.put("entityString",entity);

  when(DB.get("SomeString", queryParam)).thenReturn(mockResponse);

但是不匹配。我感觉在实际调用时无法匹配 Object[]String [] 。请帮助我。

最佳答案

明确的答案(匹配 map )

现在很明显,您想要做的是匹配 Map<String, Object[]>而不是 mock 一个,这可能很棘手:即使 Map支持equals数组默认情况下通过同一性而不是深度相等进行比较。在这种情况下,我会使用一些 Hamcrest matchers :

private Matcher<Map<String, Object[]>> hasParamArray(
    String key, Object... vals) {
  return hasEntry(
      equalTo(key),
      arrayContaining(vals));
}

// elsewhere
when(DB.get(
        eq("someString"),
        argThat(hasParamArray("entityString", "entity1"))))
    .thenReturn(mockResponse);

作为替代方案,请写下答案:

when(DB.get(eq("someString"), anyMap())).thenAnswer(new Answer<Response>() {
  @Override public void answer(InvocationOnMock invocation) {
    Map<String, Object[]> map =
        (Map<String, Object[]>) invocation.getArguments()[1];
    if (/* ... */) {
      return mockResponse1;
    } else if (/* ... */) {
      return mockResponse2;
    } else {
      return defaultResponse;
    }
  }
});
<小时/>

原始答案( mock map )

请注意Object[]String[]是不兼容的类型:

Map<String, Object[]> yourMap = new HashMap<>();
String[] yourStringArray = new String[] { "hello" };

// this is a compile error, or at least it should be...
yourMap.put("foo", yourStringArray);

// ...because this would otherwise be a runtime error, which is probably
// what you're experiencing right now.
Object[] yourObjectArray = yourMap.get("foo"); // returns yourStringArray
yourObjectArray[0] = new Object();

return yourStringArray[0].length();  // oops! this is that new Object()!

您或许可以切换entity输入Object[]并完成:

// in your class with a call to MockitoAnnotations.initMocks(this) in setUp()
@Mock Map<String, Object[]> queryParam;

when(queryParam.get("someString")).thenReturn(new Object[] { "entity1" });

也就是说,我建议按照大卫在评论中所说的那样做,并使用真实的 map 。经验法则是不要模拟数据对象,并且有三个很好的理由不模拟 Map<String, Object[]> :

  1. 模拟永远不会像真实的一样好。接口(interface)可以改变,就像它们在 Java 8 中支持流一样,真正的实现将适应这些变化,而模拟则不会。在模拟真实对象时尤其如此,其中添加 final修饰符(例如)会毁掉你的模拟,而不会真正影响你的测试系统。

  2. 与数据库不同, map 很容易手动创建。许多数据库系统有很多依赖项,并且需要大量内存。 map 没有额外的依赖项,并且是极其轻量级且经过充分测试的 Java 核心组件。

    (即使它是一个完整的数据库,内存中的“假”或其他一些独立实现也会比任何合理的 Mockito 模拟更加健壮。因为 JDK 为您提供了许多合理的实现,这是一个更简单的选择。)

  3. 要适本地模拟 Map 需要等量甚至更多的工作。您的测试可能会get map 外的某些值,每个值都需要用 when 进行 stub ;可变 Map 可以简单地接受 put 的映射。如果您的系统改变了 map ,您需要预测调用并更新模拟,真正的 map 将自动具有正确的行为。

    更不用说电话 containsKey(K) , containsValue(V) , remove(Object) , size() ,以及 Map 上的许多其他方法,您需要替换它们才能进行可靠的测试。使用模拟,最简单、最合理的代码更改都会破坏您的测试,除非您以巨大的时间和可读性为代价来模拟一切

简而言之,Map 是比任何 Mockito 模拟更好的选择。

关于java - 如何在 Java 中匹配对象数组的 Map,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29613518/

相关文章:

java - 强制执行 JVM GC - 有充分的理由(我希望)

java - JAXB 仅解码 XML 文件的深层嵌套子集

java - 如何模拟本地 OAuth2RestTemplate restTemplate?

mockito - PowerMockito 似乎无法匹配和重载方法

java - Mocking Guice 提供的对象

java - 如何在mockito中模拟enum.values()

java - 将 ByteBuffer 的一部分转换回 String

java - 在 Java play 应用程序中启用 CORS 过滤器

java - LDAP:如何使用连接详细信息对用户进行身份验证

java - 如何模拟 Spring ConversionService?