Cha*_*had 0 java unit-testing mockito stubbing
我正在尝试使用'any'匹配器来存根这个getKeyFromStream方法.我已经尝试过更明确且更不明确(anyObject()),但似乎无论我尝试什么,这个存根都不会在我的单元测试中返回fooKey.
我想知道是不是因为它受到了保护,或者还有其他我遗漏或做错的事情.我有其他什么时候/然后在整个测试中的语句正在工作,但由于某种原因在这里,它不是.
注意: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;
}
}
Run Code Online (Sandbox Code Playgroud)
单元测试
@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);
}
Run Code Online (Sandbox Code Playgroud)
你的单元测试的问题是,你试图模拟你想要测试的实际类的方法,但你实际上不能调用mock方法,因为这将返回null,除非你声明一个模拟的返回值调用方法.通常,您只模拟外部依赖项.
实际上有两种方法来创建测试对象:mock和spy.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);
Run Code Online (Sandbox Code Playgroud)
要么
// method 2
doReturn(answer).when(mockedObject).methodToMock(param1, param2);
Run Code Online (Sandbox Code Playgroud)
不同之处在于,method 1将执行方法实现,而后者则不执行.如果您处理spy对象很重要,因为有时您不想在调用的方法中执行实际代码,而只是替换代码或返回预定义的值!
虽然Mockito和PowerMock提供了一个doCallRealMethod()你可以定义而不是doReturn(...)或者doThrow(...),它将调用并执行你的真实对象中的代码,并忽略任何模拟的方法返回语句.但是,在您想要模拟测试类的方法的情况下,这不是很有用.
方法实现可以被"覆盖"
doAnswer(Answer<T>() {
@Override
public T answer(InvocationOnMock invocation) throws Throwable {
...
}
)
Run Code Online (Sandbox Code Playgroud)
您可以在其中声明调用方法的逻辑应该是什么.您可以利用它来返回受保护方法的模拟结果,因此如下所示:
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));
}
}
Run Code Online (Sandbox Code Playgroud)
上述工程的代码,但是请注意,这有相同的语义简单地宣布一个返回值的getKey(...)作为
doReturn(mockedKey).when(sut).getKey(anyString());
Run Code Online (Sandbox Code Playgroud)
尝试仅getKeyFromStream(...)使用以下内容进行修改:
doReturn(mockedKey)
.when(sut).getKeyFromStream(any(InputStream.class), anyString());
Run Code Online (Sandbox Code Playgroud)
如果不修改getKey(...)您的被测系统(SUT)将无法实现任何内容,因为getKey(...)将执行真正的代码.但是,如果您模拟了sut-object,则无法在您的// Act部分中调用该方法,因为这将返回null.如果你试试
doCallRealMethod().when(sut).getKey(anyString());
Run Code Online (Sandbox Code Playgroud)
模拟对象上,真正的方法woulb被调用,如事先mentiond,这也将调用真正的实现getKeyFromStream(...)和getKeyStream(...)你指定什么作为模拟方法不管.
正如你自己可能看到的那样,你所测试的实际课程的模拟方法并没有那么有用,给你带来的负担比提供任何好处更多.因此,如果您想要或者需要测试私有/受保护的方法,或者您坚持只测试公共API(我建议),则由您或您的企业策略决定.您还可以重构代码以提高可测试性,尽管重构的主要目的应该是改进代码的整体设计.
| 归档时间: |
|
| 查看次数: |
22738 次 |
| 最近记录: |