是否有一种干净的方法来用泛型参数模拟类?假设我必须模拟一个类Foo<T>,我需要传递到一个方法,期望Foo<Bar>。我可以很容易地做到以下几点:

Foo mockFoo = mock(Foo.class);
when(mockFoo.getValue).thenReturn(new Bar());

假设getValue()返回泛型类型t,但当我后来将它传递给一个期望Foo<Bar>的方法时,它将有小猫。选角是唯一的方法吗?


当前回答

这里有一个有趣的例子:方法接收泛型集合并返回相同基类型的泛型集合。例如:

Collection<? extends Assertion> map(Collection<? extends Assertion> assertions);

这个方法可以通过组合Mockito anyCollectionOf匹配器和Answer来模拟。

when(mockedObject.map(anyCollectionOf(Assertion.class))).thenAnswer(
     new Answer<Collection<Assertion>>() {
         @Override
         public Collection<Assertion> answer(InvocationOnMock invocation) throws Throwable {
             return new ArrayList<Assertion>();
         }
     });

其他回答

我认为你确实需要施放它,但这应该不会太糟:

Foo<Bar> mockFoo = (Foo<Bar>) mock(Foo.class);
when(mockFoo.getValue()).thenReturn(new Bar());

另一种解决方法是使用@Mock注释。 不是所有情况下都有效,但看起来更性感:)

这里有一个例子:

@RunWith(MockitoJUnitRunner.class)
public class FooTests {

    @Mock
    public Foo<Bar> fooMock;
    
    @Test
    public void testFoo() {
        when(fooMock.getValue()).thenReturn(new Bar());
    }
}

MockitoJUnitRunner初始化带有@Mock注释的字段。

所以你得到了这个:

Foo mockFoo = mock(Foo.class);

解决方法,从我最不喜欢的开始到最喜欢的:

使用@SuppressWarnings("unchecked")注释。这并不能真正解决问题,但你将不再收到警告。

@SuppressWarnings("unchecked")
Foo mockFoo = mock(Foo.class);
when(mockFoo.getValue).thenReturn(new Bar());

把它。不幸的是,它仍然给出了警告。所以你也需要在这里使用注释:

@SuppressWarnings("unchecked")
Foo<Bar> mockFoo = (Foo<Bar>) mock(Foo.class);
when(mockFoo.getValue).thenReturn(new Bar());

使用@Mock注释。不会有任何警告。这里,什么时候可以加入到实际测试中。

@Mock
public Foo<Bar> fooMock;

使用@MockBean注释。这将直接创建一个模拟bean。没有警告。

@MockBean
public Foo<Bar> fooMock;

您总是可以创建一个中间类/接口来满足您想要指定的泛型类型。例如,如果Foo是一个接口,您可以在测试类中创建以下接口。

private interface FooBar extends Foo<Bar>
{
}

在Foo是一个非final类的情况下,你可以用下面的代码扩展这个类,并做同样的事情:

public class FooBar extends Foo<Bar>
{
}

然后你可以使用下面的代码来使用上面的例子:

Foo<Bar> mockFoo = mock(FooBar.class);
when(mockFoo.getValue()).thenReturn(new Bar());

这里有一个有趣的例子:方法接收泛型集合并返回相同基类型的泛型集合。例如:

Collection<? extends Assertion> map(Collection<? extends Assertion> assertions);

这个方法可以通过组合Mockito anyCollectionOf匹配器和Answer来模拟。

when(mockedObject.map(anyCollectionOf(Assertion.class))).thenAnswer(
     new Answer<Collection<Assertion>>() {
         @Override
         public Collection<Assertion> answer(InvocationOnMock invocation) throws Throwable {
             return new ArrayList<Assertion>();
         }
     });