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

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

假设getValue()返回泛型类型t,但当我后来将它传递给一个期望Foo<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<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。

为什么不用间谍

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

(在我看来)最简单和最易读的方法是使用方法级注入。

这将导致在测试方法中拥有所有测试数据。这将使您的测试类保持干净,因为没有“浮动”mock。

@ExtendWith(MockitoExtension.class)
public class SomeClassTest {

    @Test
    void someTestMethod(@Mock Foo<Bar> fooMock) {
        // do something with your mock
    }
    
}

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

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