我在Presenter
:
@UiThread
public void tryToReplaceLogo(String emailInitiallySearchedFor, String logoUrl) {
if(isTheEmailWeAskedApiForStillTheSameAsInTheInputField(emailInitiallySearchedFor)){
if (!TextUtils.isEmpty(logoUrl)) {
downloadAndShowImage(logoUrl);
} else {
view.displayDefaultLogo();
}
}
}
public void downloadAndShowImage(String url) {
final Target target = new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
view.displayLogoFromBitmap(bitmap);
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
Picasso.with(view.getViewContext()).load(url).resize(150, 150).centerInside().into(target);
}
这个单元测试它:
@Test
public void testDisplayLogoIfValidUrlReturnedAndEmailEnteredIsTheSame() throws Exception {
when(loginView.getUserName()).thenReturn(VALID_EMAIL);
when(loginView.getViewContext()).thenReturn(context);
loginLogoFetcherPresenter.onValidateEmailEvent(createSuccessfulValidateEmailEvent(VALID_EMAIL));
waitForAsyncTaskToKickIn();
verify(loginView).displayLogoFromBitmap((Bitmap) anyObject());
}
但是,永远不会调用displayLogoFromBitmap
方法,因此我的测试失败了。我需要模拟Target
依赖项来调用onBitmapLoaded
方法,但我不知道如何。
可能我需要创建一个实现Target
的静态内部类,以便我可以在我的测试中设置一个Mocked实现,但是如何在模拟上调用onBitmapLoaded
方法呢? / p>
编辑:
我现在在LoginPresenter中为Picasso设置了一个setter字段。在生产中,(因为我正在使用AndroidAnnotations),我在
中实例化它@AfterInject
void initPicasso() {
picasso = Picasso.with(context):
}
在我的测试中,我像这样嘲笑毕加索:
@Mock
Picasso picasso;
@Before
public void setUp() {
picasso = mock(Picasso.class, RETURNS_DEEP_STUBS);
}
(我不记得为什么,但我现在不能使用Mockito 2.我认为这与某些东西不兼容)
在我的测试案例中,我达到了这一点,我不知道该怎么做:
@Test
public void displayLogoIfValidUrlReturnedAndEmailEnteredIsTheSame() throws Exception {
when(loginView.getUserName()).thenReturn(VALID_EMAIL);
when(loginView.getViewContext()).thenReturn(context);
when(picasso.load(anyString()).resize(anyInt(), anyInt()).centerInside().into(???)) // What do I do here?
loginLogoFetcherPresenter.onValidateEmailEvent(createSuccessfulValidateEmailEvent(VALID_EMAIL));
waitForAsyncTaskToKickIn();
verify(loginView).displayLogoFromBitmap((Bitmap) anyObject());
}
答案 0 :(得分:3)
我需要模拟Target依赖
没有; 不要模拟被测系统。目标与任何事物一样,都是该系统的一部分;毕竟,你为它编写了代码。请记住,一旦你模拟了一个类,你就会提交不使用它的实现,所以试图模拟Target来调用onBitmapLoaded
是没有意义的。
这里发生的事情是你将目标 - 这是你编写的值得测试的真实代码 - 传递给毕加索,这是你写的但不依赖的外部代码。这使得毕加索成为值得嘲笑的依赖者,但需要注意的是,如果他们改变了(例如方法变成最终的话),那么你无法控制的嘲弄界面会让你陷入困境。
所以:
RETURNS_SELF
选项或other Builder pattern strategies的主要候选者。Picasso.with
创建它。此时您可能不需要存根LoginView.getViewContext()
,这是一件好事,因为您的测试可以与难以测试的Android系统类进行较少的交互,并且因为您进一步分离了对象创建(Picasso)来自商业逻辑。RequestCreator.into
上调用的Target方法。verify(view, never()).onBitmapLoaded(any())
。target.onBitmapLoaded
。此时您已拥有target
实例,并且从测试中明确调用您的代码(在您的测试系统中编写)应该感觉正确。verify(view).onBitmapLoaded(any())
。请注意,现有的测试助手名为MockPicasso,但似乎需要Robolectric,我自己也没有检查过它的安全性或实用性。