gpt4 book ai didi

android - 如何在不影响生产数据库的情况下测试使用 ContentProvider 的 Activity?

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:43:37 26 4
gpt4 key购买 nike

问题

我有两个要测试的 Android 类:

我目前有两个测试类:

  • CommentContentProviderTest , 它扩展了 ProviderTestCase2<CommentContentProvider>并使用 MockContentResolver .这很好用。
  • CommentActivityTest , 它扩展了 ActivityInstrumentationTestCase2<CommentActivity> .这工作正常,除了 CommentActivity 的部分该访问 CommentContentProvider .

问题是,当CommentActivity访问 CommentContentProvider , 它通过标准 ContentResolver 来实现:

ContentResolver resolver = getContentResolver();
Cursor cursor = resolver().query(...);

因此,当CommentActivityTest运行,它启动 CommentActivity ,它访问(读取和写入)生产数据库,如以上两行所示。

我的问题是如何制作CommentActivity使用标准 ContentResolver在生产中但MockContentResolver在测试期间。

相关问题

可能的解决方案

如果我能注入(inject)一个 ContentResolver 就好了(可能是 MockContentResolverRenamingDelegatingContext )通过 Intent开始 CommentActivity ,但我不能那样做,因为 Context s 不是 Parcelable .

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

选项 1

将调试标志添加到 Intent开始 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();
}
:
}

我不喜欢这个选项,因为我不喜欢将与测试相关的代码放在我的非测试类中。

选项 2

使用抽象工厂模式传递一个Parcelable提供真实 ContentProvider 的类或 MockContentProvider :

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;
}
}

在生产中,我(通过 Intent )传递了一个 RealContentResolverFactory 的实例, 在测试中我传递了一个 MockContentResolverFactory 的实例.由于两者都没有任何状态,因此它们很容易 Parcelable/Serializable。

我对这种方法的担忧是我不想成为 "that guy"当存在更简单的方法时,谁会过度使用设计模式。

选项 3

将以下方法添加到CommentActivity :

public void static setContentResolver(ContentResolver) {
:
}

这比选项 1 更简洁,因为它将创建 ContentResolverCommentActivity之外, 但是,与选项 1 一样,它需要修改被测类。

选项 4

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

private class MyContext extends RenamingDelegatingContext {
MyContext(Context context) {
super(context, FILE_PREFIX);
}

@Override
public ContentResolver getContentResolver() {
return mResolver;
}
}

这可行,不需要修改被测类,但增加了更多的复杂性,因为 ActivityUnitTestCase<CommentActivity>.startActivity() cannot be called in the setUp( ) method, per the API .

另一个不方便的地方是activity必须在触摸模式下测试,setActivityInitialTouchMode(boolean)ActivityInstrumentationTestCase2<T> 中定义但不是 ActivityUnitTestCase<T> .

FWIW,我有点着迷于把它做好,因为我将在我教授的 Android 开发类(class)中展示它。

最佳答案

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

关于android - 如何在不影响生产数据库的情况下测试使用 ContentProvider 的 Activity?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22585067/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com