java 使用 Retrofit 和 Mockito 进行 Android 单元测试
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29981022/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android Unit Test with Retrofit and Mockito
提问by Steve Haley
I separated retrofit api calls methods from the activity code and I want to do a unit test on these methods, one example: The interface:
我将改造 api 调用方法与活动代码分开,我想对这些方法进行单元测试,一个例子:接口:
public interface LoginService {
@GET("/auth")
public void basicLogin(Callback<AuthObject> response);
}
and this is the method that do the call, in the main activity I get the object by the event bus.
这是调用的方法,在主要活动中,我通过事件总线获取对象。
public class AuthAPI {
private Bus bus;
LoginService loginService;
public AuthAPI(String username, String password) {
this.bus = BusProvider.getInstance().getBus();
loginService = ServiceGenerator.createService(LoginService.class,
CommonUtils.BASE_URL,
username,
password);
}
public void Login() {
loginService.basicLogin(new Callback<AuthObject>() {
@Override
public void success(AuthObject authObject, Response response) {
bus.post(authObject);
}
@Override
public void failure(RetrofitError error) {
AuthObject authObject = new AuthObject();
authObject.setError(true);
bus.post(authObject);
}
});
}
}
And here the test
这里是测试
@RunWith(MockitoJUnitRunner.class)
public class AuthCallTest extends TestCase {
AuthAPI authAPI;
@Mock
private LoginService mockApi;
@Captor
private ArgumentCaptor<Callback<AuthObject>> cb;
@Before
public void setUp() throws Exception {
authAPI = new AuthAPI("username", "password");
MockitoAnnotations.initMocks(this);
}
@Test
public void testLogin() throws Exception {
Mockito.verify(mockApi).basicLogin((cb.capture()));
AuthObject authObject = new AuthObject();
cb.getValue().success(authObject, null);
assertEquals(authObject.isError(), false);
}
}
when I launch the test I have this error
当我启动测试时出现此错误
Wanted but not invoked:
mockApi.basicLogin(<Capturing argument>);
-> at AuthCallTest.testLogin(AuthCallTest.java:42)
Actually, there were zero interactions with this mock.
What I did wrong, this is driving me crazy I tried to follow this guide without success: http://www.mdswanson.com/blog/2013/12/16/reliable-android-http-testing-with-retrofit-and-mockito.html
我做错了什么,这让我发疯了我试图按照本指南没有成功:http: //www.mdswanson.com/blog/2013/12/16/reliable-android-http-testing-with-retrofit-and -mockito.html
someone help me :(
谁来帮帮我 :(
回答by Steve Haley
The article isn't very clear as it misses out the setup steps. By visiting the GitHub projectlinked in the article, you can see the full source code which explains those missing steps:
这篇文章不是很清楚,因为它错过了设置步骤。通过访问文章中链接的GitHub 项目,您可以看到解释这些缺失步骤的完整源代码:
1) The code samples are extracted from a test class testing a specific activity. As part of the setup (i.e. in @Before
), it replaces the Activity's reference to a GitHub API implementation with a mock one. It then calls the Activity's onCreate()
.
1) 代码示例是从测试特定活动的测试类中提取的。作为设置的一部分(即在 中@Before
),它将活动对 GitHub API 实现的引用替换为模拟的引用。然后它调用 Activity 的onCreate()
.
2) During onCreate()
, the activity makes a call to the now-replaced GitHub API, passing in its Callback
object.
2) 在 期间onCreate()
,活动调用现在替换的 GitHub API,传入其Callback
对象。
Those first two steps explain why the Mockito.verify(mockApi).repositories(Mockito.anyString(), cb.capture());
step at the beginning of each test works. As the test is run after @Before
, the mockApi has indeed had a call on its repositories()
method.
前两个步骤解释了为什么Mockito.verify(mockApi).repositories(Mockito.anyString(), cb.capture());
每个测试开始时的步骤有效。当测试在 之后运行时@Before
,mockApi 确实调用了它的repositories()
方法。
The rest of the code is easier to understand once that's in place. As he's only created a mockApi
, but not changed the actual Callback
being used, the activity's content is changed. The rest of the code then verifies that those changes have taken place, either by checking a ListView or the Toasts.
一旦到位,其余的代码就更容易理解了。由于他只创建了一个mockApi
,但没有改变实际Callback
使用的,因此活动的内容发生了变化。然后,其余代码通过检查 ListView 或 Toast 来验证这些更改是否发生。
So to answer your question, you need to:
因此,要回答您的问题,您需要:
1) At the start of your test method, replace the AuthAPI's loginService object with your mockApi object, then call AuthAPI.Login()
.
1) 在您的测试方法开始时,将 AuthAPI 的 loginService 对象替换为您的 mockApi 对象,然后调用AuthAPI.Login()
.
2) Use verify()
as you already are to check that the function has been called.
2) 照verify()
原样使用来检查函数是否已被调用。
3) Create a sample AuthObject
and pass it to the cb.getValue().success()
function.
3) 创建一个样本AuthObject
并将其传递给cb.getValue().success()
函数。
4) Obtain the AuthObject
from your Bus
and assert that it is the same one you sent to the callback.success()
function.
4)AuthObject
从您那里获取Bus
并断言它与您发送给callback.success()
函数的相同。
This tests that your AuthAPI.Login()
correctly sends to your Bus
the AuthObject
that it would retrieve from Retrofit.
这会测试您AuthAPI.Login()
是否正确地将其发送给您Bus
的AuthObject
s,它将从 Retrofit 中检索到。
(I realise the SO question was written some time ago, but as I came across the same article and had the same confusion very recently, I thought this answer could be useful for others.)
(我意识到 SO 问题是前一段时间写的,但是当我最近遇到同一篇文章并且有同样的困惑时,我认为这个答案可能对其他人有用。)
回答by user2143491
The problem is that you call verify
at the wrong moment: the purpose of verify
is to verify that the interactions with mockApi were what you expected. So normally you would see something like:
问题是您verify
在错误的时刻调用:目的verify
是验证与 mockApi 的交互是否符合您的预期。所以通常你会看到类似的东西:
authApi.login();
Mockito.verify(mockApi).basicLogin((cb.capture()));
That's also what the error message is telling you: verify
expected basicLogin
to be called but it wasn't.
这也是错误消息告诉您的内容:verify
预期basicLogin
会被调用,但事实并非如此。
I've read that article too and felt there was something missing. I don't actually undestand argument capture yet. So can't help you with that :)
我也读过那篇文章,觉得少了点什么。我实际上还没有理解参数捕获。所以无法帮助你:)