Mockito嘲笑when()两种不同类型的泛型方法

时间:2018-03-16 08:41:15

标签: java generics mockito

我有两个类Generic<T, R>的通用对象:

Generic<TypeA, TypeB> genericOne;
Generic<TypeB, TypeC> genericTwo;

我必须嘲笑:

when(someObject.someMethod(Matchers.<Generic<TypeA, TypeB>>any()))
                .thenReturn(responseOne());

when(someObject.someMethod(Matchers.<Generic<TypeB, TypeC>>any()))
                .thenReturn(responseTwo());

问题是,由于类型擦除,mockito不会看到这两个方法调用之间的区别 - 它都被识别为Generic<T, R>类。

有没有办法区分这两种方法调用?

2 个答案:

答案 0 :(得分:2)

Mockito并不知道在any()调用之前指定了哪些泛型,无论如何它并不重要。

模拟行为记录中预期的参数必须依赖:

  • 值(以equals()
  • 表示
  • 或者如果equals()不充分,则以捕获者为准
  • any()如果模拟调用中的参数值在测试夹具中不重要或不知道

这些永远不必依赖于指定的泛型。

要有一个好例子,请查看Mockito.anyCollectionOf(Class<T> clazz)Mockito.anyMapOf(Class<K> keyClazz, Class<V> valueClazz)

这些方法知道传递的类,但无论如何,它们的规范都说明了:

  

此方法不进行任何类型检查,只有避免   在代码中强制转换。然而,这可能会改变(类型检查可能会   在未来的主要版本中添加)。

一般来说,您要检查的是使用期望参数调用模拟方法而不是任何参数:因此any()永远不会实现它。
因此,尝试仅检查泛型类型,但接受任何值作为参数似乎是反模式嘲弄。

在您的情况下,如果equals()不便于when()录音中的匹配,请将Mockito捕手与verify()一起使用,并在执行模拟后进行检查。

答案 1 :(得分:1)

我不认为可以区分两者,因为通用类型已被删除。但还有其他选择。

您可以将此次调用与特定订单相结合,这样即使mockito无法区分它们,它也会返回预期值。这是通过链接thenReturn方法完成的。第一次调用返回responseOne(),第二次调用返回responseTwo()

when(someObject.someMethod(Matchers.<Generic<TypeA, TypeB>>any()))
    .thenReturn(responseOne())
    .thenReturn(responseTwo());

但这并不是最佳选择,因为如果您的实施发生变化,此测试将会中断。所以这是第二种选择。

您可以为此对象实现自定义Fake。这样你就可以更好地控制这个实例的行为方式。例如。

class SomeObjectFake {

    private final SomeResponse response;

    public SomeObject(SomeResponse response) {
        this.response = response;
    }

    public SomeResponse someMethod(Generic<TypeA, TypeB> arg) {
        // Decide what to return
        return response;
    }
}