Android 如何测试使用ContentProvider而不影响生产数据库的活动?

Android 如何测试使用ContentProvider而不影响生产数据库的活动?,android,dependency-injection,android-testing,android-contentresolver,abstract-factory,Android,Dependency Injection,Android Testing,Android Contentresolver,Abstract Factory,问题 我想测试两个Android类: CommentContentProvider,它扩展并由 CommentActivity,它通过 我目前有两个测试班: CommentContentProviderTest,它扩展了ProviderTestCase2,并使用。这个很好用 CommentActivityTest,它扩展了ActivityInstrumentationTestCase2。除了访问CommentContentProvider的CommentActivity部分之外,这一切都很

问题

我想测试两个Android类:

  • CommentContentProvider
    ,它扩展并由
  • CommentActivity
    ,它通过
我目前有两个测试班:

  • CommentContentProviderTest
    ,它扩展了
    ProviderTestCase2
    ,并使用。这个很好用
  • CommentActivityTest
    ,它扩展了
    ActivityInstrumentationTestCase2
    。除了访问
    CommentContentProvider
    CommentActivity
    部分之外,这一切都很好
问题在于,当
CommentActivity
访问
CommentContentProvider
时,它通过标准
ContentResolver
进行访问:

ContentResolver resolver = getContentResolver();
Cursor cursor = resolver().query(...);
public class CommentActivity extends Activity {
    public static final String FACTORY = "CONTENT RESOLVER FACTORY";
    private ContentResolver mResolver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        :
        ContentResolverFactory factory = getIntent().getParcelableExtra(FACTORY);
        mResolver = factory.getContentResolver(this);
        :
    }
因此,当运行
CommentActivityTest
时,它将启动
CommentActivity
,它将访问(读取和写入)生产数据库,如上面两行所示

我的问题是如何使
CommentActivity
在生产中使用标准的
ContentResolver
,而在测试过程中使用
MockContentResolver

相关问题

  • 这与我在测试ContentProviders时发现的其他问题不同,因为这些问题可以扩展android.test类,这些类是为测试ContentProviders而设计的,而我需要扩展一个类来测试
    活动
  • 这是类似的,这也是我张贴,但没有回答。如果有帮助的话,我现在愿意使用第三方框架
  • 是相关的,并导致下面选项1中的解决方案,但我不知道这是否是我的情况下的最佳解决方案
可能的解决方案

如果我可以通过启动
CommentActivity
的注入
ContentResolver
(可能是
MockContentResolver
RenamingDelegatingContext
),那就太好了,但我不能这样做,因为s不是

以下哪个选项是最好的,或者有更好的选项吗

选择1

将调试标志添加到启动“注释”活动的
Intent

public class CommentActivity extends Activity {
    public static final String DEBUG_MODE = "DEBUG MODE";
    private ContentResolver mResolver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        :
        // If the flag is not present, debugMode will be set to false.
        boolean debugMode = getIntent().getBooleanExtra(DEBUG_MODE, false);
        if (debugMode) {
            // Set up MockContentResolver or DelegatingContextResolver...
        } else {
            mResolver = getContentResolver();
        }
        :
    }
public void static setContentResolver(ContentResolver) {
  :
}
我不喜欢这个选项,因为我不喜欢将测试相关的代码放在我的非测试类中

选择2

使用抽象工厂模式传递一个
Parcelable
类,该类提供真正的
ContentProvider
MockContentProvider

ContentResolver resolver = getContentResolver();
Cursor cursor = resolver().query(...);
public class CommentActivity extends Activity {
    public static final String FACTORY = "CONTENT RESOLVER FACTORY";
    private ContentResolver mResolver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        :
        ContentResolverFactory factory = getIntent().getParcelableExtra(FACTORY);
        mResolver = factory.getContentResolver(this);
        :
    }
我还有:

public abstract class ContentResolverFactory implements Parcelable {
    public abstract ContentResolver getContentResolver(Context context);
}

public abstract class RealContentResolverFactory extends ContentResolverFactory
    public ContentResolver getContentResolver(Context context) {
        return context.getContextResolver();
    }
}

public abstract class MockContentResolverFactory extends ContentResolverFactory
    public ContentResolver getContentResolver(Context context) {
        MockContentResolver resolver = new MockContentResolver();
        // Set up MockContentResolver...
        return resolver;
    }
}
在生产中,我传入(通过一个意图)一个
RealContentResolverFactory
的实例,在测试中我传入一个
MockContentResolverFactory
的实例。因为两者都没有任何状态,所以它们很容易打包/序列化

我对这种方法的担心是,我不想在存在更简单的方法时过度使用设计模式

选择3

将以下方法添加到
CommentActivity

public class CommentActivity extends Activity {
    public static final String DEBUG_MODE = "DEBUG MODE";
    private ContentResolver mResolver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        :
        // If the flag is not present, debugMode will be set to false.
        boolean debugMode = getIntent().getBooleanExtra(DEBUG_MODE, false);
        if (debugMode) {
            // Set up MockContentResolver or DelegatingContextResolver...
        } else {
            mResolver = getContentResolver();
        }
        :
    }
public void static setContentResolver(ContentResolver) {
  :
}
这比选项1更简洁,因为它将
ContentResolver
的创建置于
CommentActivity
之外,但与选项1一样,它需要修改测试中的类

选择4

CommentActivityTest
扩展
ActivityUnitTestCase
而不是
ActivityInstrumentationTestCase2
。这使我可以通过设置
CommentActivity
的上下文。我传递的上下文覆盖通常的
getContentResolver()
,以使用
MockContentResolver
(我在别处初始化)

这是可行的,不需要修改被测试的类,但会增加复杂性,因为

另一个不便之处是,活动必须在触摸模式下进行测试,并在
活动仪表测试用例2中定义,但在
活动单元测试用例中未定义


FWIW,我对这一点有点着迷,因为我将在我教的Android开发课上介绍它。

选项2对我来说似乎是最好的。我不担心工厂的使用;我更担心的是导致远距离行为改变的意图。但是其他解决方案将非生产代码放在生产代码中,因此您测试的内容与生产中的工作方式不太一样。希望这能有所帮助。

我对选项2的工作原理感到困惑。如何在产品与测试中选择实际工厂?@NamshubWriter,感谢阅读。我补充了一个问题:在生产中,我传入(通过一个意图)RealContentResolveFactory的一个实例,在测试中传入MockContentResolveFactory的一个实例。由于两者都没有任何状态,因此它们很容易进行打包/序列化。存在一个小的拼写错误。在选项2中,getContextResolver应该是getContentResolver。在相同的情况下。我喜欢选项3,但不幸的是,将其保留在静态字段中会导致内存泄漏(如as 2.2中所警告的)@EllenSpertus:我刚刚就这个主题发布了一个我自己的问题:谢谢你的回答。寂静之声震耳欲聋。:-)