Is it possible to mock android.accounts.AccountManager?

1,017 views
Skip to first unread message

Bor-Yeh Shen

unread,
Jul 15, 2010, 7:29:54 AM7/15/10
to Android Mock Discussion
Hi,

I tried to mock android.accounts.AccountManager in my unit test, but
it failed. It may because there is no any public constructor in
AccountManager. So, I am wondering if there is any way to mock
AccountManager?

thanks in advance,
Bor-yeh


My sample code:

import android.accounts.AccountManager;

@UsesMocks(AccountManager.class)
public void testGetAccount() {
AccountManager mockManager =
AndroidMock.createMock(AccountManager.class);
......
AndroidMock.expect(mockManager.getAccounts()).andReturn(accounts);
......
}

Error messages:

java.lang.RuntimeException: Could not find mock for
android.accounts.AccountManager -- Make sure to run the
MockGenerator.jar on your test jar, and to build the Android test APK
using the modified jar created by MockGenerator
at
com.google.android.testing.mocking.AndroidMock.getInterfaceFor(AndroidMock.java:
2786)
at
com.google.android.testing.mocking.AndroidMock.createMock(AndroidMock.java:
187)
at
com.google.android.testing.mocking.AndroidMock.createMock(AndroidMock.java:
157)
......

Log:

NOTE : Start Processing Annotations
NOTE : Processing [public void testGetAccount() ]
NOTE : Adding Class to Mocking List: android.accounts.AccountManager
NOTE : Found 1 classes to mock
NOTE : Mocking class android.accounts.AccountManager
NOTE : Found 0 mocked classes to save
NOTE : Finished Processing Mocks
NOTE : Start Processing Annotations
NOTE : Processing []
NOTE : Found 0 classes to mock
NOTE : Found 0 mocked classes to save
NOTE : Finished Processing Mocks

Stephen Woodward

unread,
Jul 15, 2010, 7:45:46 AM7/15/10
to androi...@googlegroups.com
Hi Bor-yeh,

If there's no public (or protected) constructor, you can't directly mock it.

With a bit of refactoring, though, you could still use Android Mock in most cases.  Instead of calling the AccountManager directly, you can create your own class with the same methods as AccountManager, and mock that.

E.g.

public class AccountManagerDelegate {
    private AccountManager realManager;
    public AccountManagerDelegate(Context context) {
        realManager = AccountManager.get(context);
    }

    public void clearPassword(Account account) {
        realManager.clearPassword(account);
    }

    // etc...
}

Replace all calls to AccountManager in your code with calls to AccountManagerDelegate.  Then, you can mock AccountManagerDelegate in your tests.  It should be a straightforward 1 to 1 replacement.

As for the Context object (in tests), use a Context object which you can get from your test case (see http://developer.android.com/reference/android/test/AndroidTestCase.html#getContext()).

Hopefully that should get you going.  Let me know if you have any troubles.


Thanks,

Steve


(Small print notice):
This refactoring is not a perfectly generic solution, since if you need to pass an AccountManager object into code that you can't modify, then you can't make this refactoring.  (For example, if you tried this with the Account class (create AccountDelegate), it wouldn't work well, because AccountManager.setPassword(Account, String) wouldn't accept an AccountDelegate.  Fortunately, Account is mockable, so you don't need this pattern for Account.)

If all you do is retrieve an AccountManager object and then invoke methods on it, this is one of the easiest approaches.

Bor-Yeh Shen

unread,
Jul 16, 2010, 8:18:52 AM7/16/10
to Android Mock Discussion
Hi Steve,

After refactoring my code, it works without any problem now.

Thanks very much for your fast answer.

Bor-yeh

On 7月15日, 下午7時45分, Stephen Woodward <sd.woodwar...@googlemail.com>
wrote:
> Hi Bor-yeh,
>
> If there's no public (or protected) constructor, you can't directly mock it.
>
> With a bit of refactoring, though, you could still use Android Mock in most
> cases.  Instead of calling the AccountManager directly, you can create your
> own class with the same methods as AccountManager, and mock that.
>
> E.g.
>
> public class AccountManagerDelegate {
>     private AccountManager realManager;
>     public AccountManagerDelegate(Context context) {
>         realManager = AccountManager.get(context);
>     }
>
>     public void clearPassword(Account account) {
>         realManager.clearPassword(account);
>     }
>
>     // etc...
>
> }
>
> Replace all calls to AccountManager in your code with calls to
> AccountManagerDelegate.  Then, you can mock AccountManagerDelegate in your
> tests.  It should be a straightforward 1 to 1 replacement.
>
> As for the Context object (in tests), use a Context object which you can get
> from your test case (seehttp://developer.android.com/reference/android/test/AndroidTestCase.h...()
> ).
Reply all
Reply to author
Forward
0 new messages