首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用mockito模拟AccountManager

使用mockito模拟AccountManager
EN

Stack Overflow用户
提问于 2014-11-14 18:57:01
回答 2查看 3.3K关注 0票数 2

我使用mockito来模拟活动测试中的AccountManager。

因此,我的测试代码如下:

代码语言:javascript
复制
public class PressuresListActivityUnitTest extends
    ActivityUnitTestCase<PressuresListActivity> {

// Test data.
private static final String ACCOUNT_TYPE = "com.example.android";
private static final Account ACCOUNT_1 = new Account("account1@gmail.com", ACCOUNT_TYPE);
private static final Account ACCOUNT_2 = new Account("account2@gmail.com", ACCOUNT_TYPE);
private static final Account[] TWO_ACCOUNTS = { ACCOUNT_1, ACCOUNT_2 };

@Mock
private AccountManager mMockAccountManager;

public PressuresListActivityUnitTest() {
    super(PressuresListActivity.class);
}

@Override
protected void setUp() throws Exception {
    super.setUp();

    setupDexmaker();
    // Initialize mockito.
    MockitoAnnotations.initMocks(this);
}

public void testAccountNotFound() {
    Mockito.when(mMockAccountManager.getAccounts())
            .thenReturn(TWO_ACCOUNTS);

    Intent intent = new Intent(Intent.ACTION_MAIN);
    startActivity(intent, null, null);
}

/**
 * Workaround for Mockito and JB-MR2 incompatibility to avoid
 * java.lang.IllegalArgumentException: dexcache == null
 *
 * @see <a href="https://code.google.com/p/dexmaker/issues/detail?id=2">
 *     https://code.google.com/p/dexmaker/issues/detail?id=2</a>
 */
private void setupDexmaker() {
    // Explicitly set the Dexmaker cache, so tests that use mockito work
    final String dexCache = getInstrumentation().getTargetContext().getCacheDir().getPath();
    System.setProperty("dexmaker.dexcache", dexCache);
}

以及将要测试的onCreate活动方法:

代码语言:javascript
复制
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_pressures_list);

    AccountManager am = AccountManager.get(this);
    Account[] accounts = am.getAccounts();
    if (accounts.length > 0) {
        Log.i("TAG", "it works!");
    }
}

但是,当我运行测试时,AccountManager.getAccounts不会返回测试中指定的帐户。

有什么想法吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-11-18 12:24:20

经过一番研究,我终于解决了这个问题。

Android提供了一些在测试中使用的类,如MockContext、IsolatedContext。

http://developer.android.com/reference/android/test/mock/MockContext.html

http://developer.android.com/reference/android/test/IsolatedContext.html

为了完成这个任务,我创建了一个ContextWrapper子类并重写了(?)getSystemService法

根据文件:

“代理上下文的实现,该实现仅将其所有调用委托给另一个上下文。可以子类化以修改行为而不更改原始上下文。”

http://developer.android.com/reference/android/content/ContextWrapper.html

通过这种方式,我使用一个常规的AndroidActivityUnitTestCase在活动中注入了原始上下文,但根据我的需要进行了修改。

看看这个:

代码语言:javascript
复制
public class FakeContextWrapper extends ContextWrapper {

    private static final String ACCOUNT_TYPE = "com.example.android";

    private static final Account ACCOUNT_1 = new Account("account1@gmail.com", ACCOUNT_TYPE);
    private static final Account ACCOUNT_2 = new Account("account2@gmail.com", ACCOUNT_TYPE);

    private static final Account[] TWO_ACCOUNTS = { ACCOUNT_1, ACCOUNT_2 };

    @Mock
    private AccountManager mMockAccountManager;

    public FakeContextWrapper(Context base) {
        super(base);

        MockitoAnnotations.initMocks(this);
        Mockito.when(mMockAccountManager.getAccounts()).thenReturn(TWO_ACCOUNTS);
    }

   @Override
   public Object getSystemService(String name) {
       if (Context.ACCOUNT_SERVICE.equals(name)) {
           return mMockAccountManager;
       } else {
           return super.getSystemService(name);
       }
   }
}

在测试中:

代码语言:javascript
复制
public void testAccountNotFound() {
    Context context = new FakeContextWrapper(getInstrumentation().getTargetContext());
    setActivityContext(context);
    Intent intent = new Intent(Intent.ACTION_MAIN);
    startActivity(intent, null, null);
    // TODO assertions.
}

最后,所测试的活动:

代码语言:javascript
复制
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_pressures_list);

    AccountManager am = AccountManager.get(this);
    Account[] accounts = am.getAccounts();
    if (accounts.length == 0) {
        // TODO call login.
    } else {
        Log.i("TAG", "it works!");
    }
}
票数 3
EN

Stack Overflow用户

发布于 2014-11-14 20:15:17

莫奇托不是这样工作的。

代码语言:javascript
复制
import static org.mockito.Mockito.*;
...

public void testAccountNotFound() {

    AccountManager am = mock(AccountManager.class);
    when(am.getAccounts()).thenReturn(TWO_ACCOUNTS);

    // this is how you unit test something
    assertTrue(am.getAccounts().size == 2);
}

public void testMoreRealWorldExample() {

    AccountManager am = mock(AccountManager.class);
    when(am.getAccounts()).thenReturn(TWO_ACCOUNTS);

    /* try and create an account; createNewAccount() will call
       getAccounts() to find out how many accounts there already
       are in the system, and due to the above injection, it would
       think there are already two. Thus we can test to make sure
       users cannot create three or more accounts.
     */
    boolean accountCreated = am.createNewAccount();

    // maximum two accounts are allowed, so this should return false.
    assertFalse(accountCreated);
}

不能直接使用mockito在对象中任意注入值,然后运行Activity。Mockito用于单元测试您的对象,理想的情况下是对Android特定对象的最小引用,尽管某些引用是不可避免的。

请阅读食谱更接近了,因为它非常彻底。

如果你想模仿整个Activity,你需要看上去像在罗波利克

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26937001

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档