【问题标题】:Android Unit Test with Retrofit and Mockito带有 Retrofit 和 Mockito 的 Android 单元测试
【发布时间】:2015-07-10 22:33:40
【问题描述】:

我将改造 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

谁来帮帮我:(

【问题讨论】:

  • 问题是您正在关注一个已有两年多的博客。此外,该作者两年没有更新他的代码,也没有兴趣。

标签: java android unit-testing mockito retrofit


【解决方案1】:

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

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

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

前两个步骤解释了为什么每个测试开始时的Mockito.verify(mockApi).repositories(Mockito.anyString(), cb.capture()); 步骤有效。由于测试在@Before 之后运行,mockApi 确实调用了它的repositories() 方法。

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


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

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

2) 使用verify() 来检查该函数是否已被调用。

3) 创建一个示例AuthObject 并将其传递给cb.getValue().success() 函数。

4) 从您的Bus 获取AuthObject,并断言它与您发送给callback.success() 函数的那个​​相同。

这测试您的AuthAPI.Login() 是否正确发送到您的Bus,它将从Retrofit 中检索到的AuthObject


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

【讨论】:

  • 您似乎想使用 Android 活动上下文来检测您的测试。我不认为这是测试 REST API 的最纯粹的方法——应该在 JVM (junit) 上进行测试。
  • @IgorGanapolsky 如果您使用任何引用 Android SDK 的类,则无法直接在 JUnit 中的 Android 应用程序中测试 REST API,因为 JUnit 不加载 Android 类。然而,这就是上面文章的目的——如何使用 Robolectric 和 Mockito 来执行 REST API 的本地测试,而无需进行实际的服务器调用,同时仍然访问真正的 Android 类。
  • @SteveHaley 上面那篇文章的问题是它已经两年了。这在 Android 开发者意义上是古老的。该代码目前几乎无法使用。
  • @IgorGanapolsky 我将其视为示例/概念证明,而不是“这是做事的正确方式”。如果您有更新内容的链接,请随时发布。
  • @IgorGanapolsky 无法编译他的代码与 Mockito 与 Robolectric 配对是否是测试 Retrofit API 的好系统完全不同。这要追溯到他的文章非常不清楚。通过一些工作来填补空白,您可以使用他描述的系统创建工作测试。至于 Mockito+Robolectric 是否仍然是最好的方法,我不能说,因为我对替代方案不够熟悉。
【解决方案2】:

问题是您在错误的时间调用verifyverify 的目的是验证与 mockApi 的交互是否符合您的预期。所以通常你会看到类似的东西:

authApi.login();
Mockito.verify(mockApi).basicLogin((cb.capture()));

这也是错误消息告诉您的内容:verify 期望 basicLogin 被调用,但事实并非如此。

我也读过那篇文章,感觉缺少了一些东西。我实际上还不了解参数捕获。所以帮不了你:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-22
    • 1970-01-01
    • 2020-05-03
    • 1970-01-01
    相关资源
    最近更新 更多