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

时间:2015-05-01 02:56:06

标签: java android unit-testing mockito retrofit

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

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

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

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

}

这里是测试

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

当我启动测试时出现此错误

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

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

有人帮助我:(

1 个答案:

答案 0 :(得分:21)

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

1)从测试特定活动的测试类中提取代码示例。作为设置的一部分(即在@Before中),它用模拟的一个替换了Activity对GitHub API实现的引用。然后它调用活动的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()是否正确地向Bus发送了它将从Retrofit中检索到的AuthObject

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