繁体   English   中英

Mockito何时/然后不返回期望值

[英]Mockito when/then not returning expected value

我正在尝试使用“ any”匹配器对这个getKeyFromStream方法进行存根。 我尝试了更明确和不太明确的(anyObject()),但是无论我如何尝试,此存根都不会在我的单元测试中返回fooKey。

我想知道是否是因为它受到保护,或者我缺少其他东西或做错了什么。 在整个测试中,我还有其他when / then语句在起作用,但是由于某种原因,事实并非如此。

注意:getKeyFromStream通常使用byteArrayInputStream,但是我尝试将其与InputStream匹配,但都尝试了无济于事。

public class FooKeyRetriever() //Mocked this guy
{
    public FooKey getKey(String keyName) throws KeyException {

        return getKeyFromStream(getKeyStream(keyName, false), keyName);
    }

    //Stubbed this method to return a key object which has been mocked
    protected FooKey getKeyFromStream(InputStream keyStream, String keyName){
        //Some code
        return fooKey;
    }
}

单元测试

@Mock
private FooKeyRetriever mockKeyRetriever;

@Mock
private FooKey fooKey;

@Before
public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
}

@Test
public void testGetFooKey() throws Exception {



    when(foo.getKeyFromStream(any(InputStream.class),any(String.class))).thenReturn(fooKey);

    FooKey fooKey = mockKeyRetriever.getKey("irrelevant_key");

    assertNotNull(fooKey);
}

单元测试的问题在于,您正在尝试模拟要测试的实际类的方法,但实际上无法调用模拟方法,因为除非您在该方法上声明了模拟的返回值,否则它将返回null。调用的方法。 通常,您只模拟外部依赖项。

实际上,有两种创建测试对象的方法: mockspy 入门者将根据您提供的类创建一个新对象,该类的内部状态为null,并且在每个调用的方法上都返回null 这就是为什么您需要为方法调用定义某些返回值的原因。 另一方面,如果为某些方法定义了“模拟定义”,则spy会创建一个真实的对象并拦截方法调用。

Mockito和PowerMock提供了两种定义模拟方法的方法:

// method 1
when(mockedObject.methodToMock(any(Param1.class), any(Param2.class),...)
    .thenReturn(answer);
when(mockedObject, method(Dependency.class, "methodToMock", Parameter1.class, Parameter2.class, ...)
    .thenReturn(answer);

要么

// method 2
doReturn(answer).when(mockedObject).methodToMock(param1, param2);

所不同的是, method 1将执行方法实现,而后一种则不会。 如果您要处理spy对象,这很重要,因为您有时不想执行所调用方法中的真实代码,而只是替换代码或返回预定义的值!

虽然和的Mockito提供PowerMock一个doCallRealMethod()您可以定义的,而不是doReturn(...)doThrow(...)这将调用和您的真实对象中执行代码和忽略任何模拟的方法return语句。 但是,在您要模拟被测类的方法的情况下,这并不是很有用。

可以通过以下方法“覆盖”方法实现:

doAnswer(Answer<T>() { 
    @Override 
    public T answer(InvocationOnMock invocation) throws Throwable {
        ...
    }
)

您可以在其中简单地声明所调用方法的逻辑。 因此,您可以利用此方法返回受保护方法的模拟结果:

import static org.hamcrest.core.IsSame.sameInstance;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;

import java.io.InputStream;

import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

public class FooKeyRetrieverTest {

    @Test
    public void testGetFooKey() throws Exception {
        // Arrange
        final FooKeyRetriever sut = spy(new FooKeyRetriever());
        FooKey mockedKey = mock(FooKey.class);

        doReturn(mockedKey)
            .when(sut).getKeyFromStream(any(InputStream.class), anyString());
        doAnswer(new Answer<FooKey>() {

            public FooKey answer(InvocationOnMock invocation) throws Throwable {
                return sut.getKeyFromStream(null, "");
            }
        }).when(sut).getKey(anyString());

        // Act
        FooKey ret = sut.getKey("test");

        // Assert
        assertThat(ret, sameInstance(mockedKey));
    }
}

上面的代码有效,但是请注意,它的语义与简单地声明getKey(...)的返回值相同getKey(...)

doReturn(mockedKey).when(sut).getKey(anyString());

尝试仅使用getKeyFromStream(...)方式修改getKeyFromStream(...)

doReturn(mockedKey)
    .when(sut).getKeyFromStream(any(InputStream.class), anyString());

如果不修改测试中的系统(SUT)的getKey(...) ,将不会实现任何目标,因为将执行getKey(...)的真实代码。 但是,如果模拟sut对象,则无法在// Act部分中调用该方法,因为这将返回null。 如果你试试

doCallRealMethod().when(sut).getKey(anyString());

在模拟对象上,将调用真实方法,并且如前所述,这还将调用getKeyFromStream(...)getKeyStream(...)的实际实现,而不管您指定为模拟方法是什么。

正如您可能自己看到的那样,测试中的实际类的模拟方法不是那么有用,并且给您带来的负担超过了它提供的任何好处。 因此,如果您想要或需要完全测试私有/受保护的方法,或者仅坚持测试公共API(我建议这样做),则取决于您或您企业的政策。 尽管重构的主要目的应该是改善代码的总体设计,但是您也可以重构代码以提高可测试性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM