Android 单元测试与改造和 Mockito

2022-09-04 01:30:18

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

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

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

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

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

一旦到位,代码的其余部分就更容易理解。由于他只创建了一个 ,但未更改实际使用的内容,因此活动的内容已更改。然后,代码的其余部分通过检查 ListView 或 Toasts 来验证这些更改是否已发生。mockApiCallback


因此,要回答您的问题,您需要:

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

2)像您已经使用的那样检查该函数是否已被调用。verify()

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

4) 从您的中获取 ,并断言它是您发送到函数的同一个。AuthObjectBuscallback.success()

此测试您正确发送到您的,它将从改造中检索。AuthAPI.Login()BusAuthObject


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


答案 2

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

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

这也是错误消息告诉您的:预期被调用,但事实并非如此。verifybasicLogin

我也读过那篇文章,觉得缺少了一些东西。我实际上还没有取消参数捕获。所以不能帮你这个:)


推荐