是否有一种干净的方法来用泛型参数模拟类?假设我必须模拟一个类Foo<T>,我需要传递到一个方法,期望Foo<Bar>。我可以很容易地做到以下几点:
Foo mockFoo = mock(Foo.class);
when(mockFoo.getValue).thenReturn(new Bar());
假设getValue()返回泛型类型t,但当我后来将它传递给一个期望Foo<Bar>的方法时,它将有小猫。选角是唯一的方法吗?
是否有一种干净的方法来用泛型参数模拟类?假设我必须模拟一个类Foo<T>,我需要传递到一个方法,期望Foo<Bar>。我可以很容易地做到以下几点:
Foo mockFoo = mock(Foo.class);
when(mockFoo.getValue).thenReturn(new Bar());
假设getValue()返回泛型类型t,但当我后来将它传递给一个期望Foo<Bar>的方法时,它将有小猫。选角是唯一的方法吗?
当前回答
为什么不用间谍
var mock = spy(new Foo<Bar>());
when(mockFoo.getValue()).thenReturn(new Bar());
其他回答
我认为你确实需要施放它,但这应该不会太糟:
Foo<Bar> mockFoo = (Foo<Bar>) mock(Foo.class);
when(mockFoo.getValue()).thenReturn(new Bar());
对于JUnit5,我认为最好的方法是在方法参数或字段中使用@Mock @ExtendWith(MockitoExtension.class)。
下面的例子用Hamcrest匹配器演示了这一点。
package com.vogella.junit5;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
import static org.mockito.Mockito.verify;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class MockitoArgumentCaptureTest {
@Captor
private ArgumentCaptor<List<String>> captor;
@Test
public final void shouldContainCertainListItem(@Mock List<String> mockedList) {
var asList = Arrays.asList("someElement_test", "someElement");
mockedList.addAll(asList);
verify(mockedList).addAll(captor.capture());
List<String> capturedArgument = captor.getValue();
assertThat(capturedArgument, hasItem("someElement"));
}
}
有关所需的Maven/Gradle依赖项,请参阅https://www.vogella.com/tutorials/Mockito/article.html。
所以你得到了这个:
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;
正如其他答案所提到的,如果没有不安全的泛型访问和/或抑制泛型警告,直接使用mock()和spy()方法并不是一个很好的方法。
目前在Mockito项目(#1531)中有一个悬而未决的问题,即添加对使用mock()和spy()方法而不带泛型警告的支持。该问题于2018年11月开始发行,但没有任何迹象表明它将被优先考虑。根据Mockito贡献者对这个问题的评论:
鉴于.class不能很好地使用泛型,我认为在Mockito中没有任何解决方案。您已经可以使用@Mock (JUnit5扩展还允许方法参数@Mock),这应该是一个合适的替代方案。因此,我们可以保持这个问题的开放性,但它不太可能被修复,因为@Mock是一个更好的API。
JUnit5:在测试类上使用@ExtendWith(MockitoExtension.class),然后添加这个字段:
@Mock
Foo<Bar> barMock;