使用Retrofit和Mockito进行Android单元测试

12 java android unit-testing mockito retrofit

我从活动代码中分离了改进的api调用方法,我想对这些方法进行单元测试,例如:接口:

public interface LoginService {
    @GET("/auth")
    public void basicLogin(Callback<AuthObject> response);
}
Run Code Online (Sandbox Code Playgroud)

这是执行调用的方法,在主活动中,我通过事件总线获取对象.

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);
            }
        });
    }

}
Run Code Online (Sandbox Code Playgroud)

在这里测试

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

当我启动测试时,我有这个错误

Wanted but not invoked:
mockApi.basicLogin(<Capturing argument>);
-> at AuthCallTest.testLogin(AuthCallTest.java:42)
Actually, there were zero interactions with this mock.
Run Code Online (Sandbox Code Playgroud)

我做错了什么,这让我发疯了我试图按照本指南取得成功:http: //www.mdswanson.com/blog/2013/12/16/reliable-android-http-testing-with-retrofit-and -mockito.html

谁来帮帮我 :(

Ste*_*ley 21

这篇文章不太清楚,因为它错过了设置步骤.通过访问本文中链接的GitHub项目,您可以看到完整的源代码,它解释了这些缺失的步骤:

1)从测试特定活动的测试类中提取代码样本.作为设置的一部分(即in @Before),它将模拟的GitHub API实现的Activity引用替换为.然后它调用Activity onCreate().

2)在此期间onCreate(),活动调用现在替换的GitHub API,传入其Callback对象.

前两个步骤解释了为什么Mockito.verify(mockApi).repositories(Mockito.anyString(), cb.capture());每个测试开始时的步骤都有效.随着测试的运行@Before,mockApi确实对其repositories()方法进行了调用.

一旦到位,其余代码就更容易理解了.因为他只创建了一个mockApi,但没有更改实际Callback使用,活动的内容会发生变化.然后,其余代码通过检查ListView或Toasts来验证是否已发生这些更改.


所以要回答你的问题,你需要:

1)在测试方法开始时,用mockApi对象替换AuthAPI的loginService对象,然后调用AuthAPI.Login().

2)使用verify()您已经检查的功能已被调用.

3)创建一个样本AuthObject并将其传递给该cb.getValue().success()函数.

4)AuthObject从你那里获取Bus并声明它与你发送给callback.success()函数的那个相同.

这个测试,你AuthAPI.Login()正确地发送到您BusAuthObject,它将检索改造.


(我意识到SO问题是在不久前写的,但是当我遇到同一篇文章并且最近也有同样的困惑时,我认为这个答案可能对其他人有用.)