gpt4 book ai didi

java - Mockito 何时/然后不返回预期值

转载 作者:行者123 更新时间:2023-12-03 10:06:46 28 4
gpt4 key购买 nike

我正在尝试使用“任何”匹配器来 stub 此 getKeyFromStream 方法。我尝试过更加明确和不明确(anyObject()),但似乎无论我尝试什么,这个 stub 都不会在我的单元测试中返回 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 .初级类(class)将根据您提供的具有内部状态 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(...) ,这将在您的真实对象中调用和执行代码,并忽略任何模拟方法返回语句。但是,在您想要模拟被测类的方法的情况下,这并不是很有用。

方法实现可以通过以下方式“覆盖”
doAnswer(Answer<T>() { 
@Override
public T answer(InvocationOnMock invocation) throws Throwable {
...
}
)

您可以简单地声明被调用方法的逻辑应该是什么。您可以利用它来返回 protected 方法的模拟结果,因此如下所示:
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(...) 声明返回值具有相同的语义。作为
doReturn(mockedKey).when(sut).getKey(anyString());

仅尝试修改 getKeyFromStream(...)像这样:
doReturn(mockedKey)
.when(sut).getKeyFromStream(any(InputStream.class), anyString());

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

在模拟对象上,将调用真正的方法,如前所述,这也将调用 getKeyFromStream(...) 的实际实现。和 getKeyStream(...)无论您指定什么模拟方法。

正如您自己可能看到的那样,实际测试类的模拟方法并没有那么有用,并且给您带来的负担比它提供的任何好处都多。因此,如果您想要或需要测试私有(private)/ protected 方法,或者您坚持只测试公共(public) API(我会推荐),这取决于您或您的企业的政策。您也可以使用 refactor your code为了提高可测试性,尽管重构的主要目的应该是 improve the overall design of your code .

关于java - Mockito 何时/然后不返回预期值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31413337/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com