使用ContentProviders进行Android单元测试

我一直在努力解决
Android上的单元测试问题.我的应用程序使用Sqlite DB来存储车辆的详细信息.我最近添加了ContentProvider模式来检索数据(用于直接访问的数据库).

该应用程序工作正常,但我的测试偶尔在eclipse上以’run’模式运行时失败 – 它们以’debug’模式传递.在我的setUp()方法中,我创建了一个RenamingDelegatingContext,以便创建我的数据库的测试版本.所有这一切都是前缀“test”.到我的数据库的名称,以确保测试代码不触及“真正的”数据库.然后我将它传递给’数据提供者’类,以保持作为实例变量,直到第一次调用getWriteableDatabase()为止:

public class VehicleProviderTest extends InstrumentationTestCase
{

RenamingDelegatingContext renamingDelegatingContext;
@Override
protected void setUp() throws Exception
{
    super.setUp();
    if(null == renamingDelegatingContext)
    {
        renamingDelegatingContext = new RenamingDelegatingContext(getInstrumentation().getTargetContext(), "test.");

    }

    Log.d("UKMPG", "Initialising UKMPGDataProvider with test context: " + renamingDelegatingContext.getClass().toString());
    MPGDataProvider.init(getTestContext(), Constants.DATABASE_NAME);
    deleteTestDatabase();
}
}

我的ContentProvider的onCreate()方法做了类似的工作,因为它还将Context传递给数据提供者类:

    @Override
public boolean onCreate()
{
    Context context = getContext();
    Log.d("UKMPG", "ContentProvider.onCreate called. Context: " + context.getClass().toString());
    MPGDataProvider.init(getContext(), Constants.DATABASE_NAME);
    return true;
}

现在,问题;当我运行我的测试时(再次,这在调试模式下不会发生),我的ContentProvider中的onCreate()在我的setUp()方法将RenamingDelegatingContext传递给数据提供者类之后被调用,导致它被覆盖.这意味着实时数据库将用于测试(它们将失败,因为测试期望空数据库).

这里有一些logcat显示覆盖发生,注释说明发生了什么:

调用ContentProvider.onCreate并将Context传递给UKMPGDataProvider:

01-11 19:22:11.404: D/UKMPG(480): ContentProvider.onCreate called. Context: class android.app.Application
01-11 19:22:11.414: D/UKMPG(480): UKMPGDataProvider.init called. Context: class android.app.Application, db name :mpg_tracker.db

测试将RenamingDelegatingContext传递给UKMPGDataProvider:

01-11 19:22:13.234: D/UKMPG(498): Initialising UKMPGDataProvider with test context: class android.test.RenamingDelegatingContext
01-11 19:22:13.234: D/UKMPG(498): UKMPGDataProvider.init called. Context: class android.test.RenamingDelegatingContext, db name :mpg_tracker.db

ContentProvider.onCreate再次调用(不同的PID)并将ApplicationContext传递给UKMPGDataProvider,覆盖RenamingDelegatingContext:

01-11 19:22:13.254: D/UKMPG(498): ContentProvider.onCreate called. Context: class android.app.ApplicationContext
01-11 19:22:13.254: D/UKMPG(498): UKMPGDataProvider.init called. Context: class android.app.ApplicationContext, db name :mpg_tracker.db

首次调用getWriteableDatabase(),因此将使用错误的Context创建数据库:

01-11 19:22:13.265: D/UKMPG(498): database null - going to create it

又发生了一次对ContentProvider.onCreate的调用!这次有一个常规的Context.然而,损坏已经完成,所以这并没有什么区别:

01-11 19:22:13.265: D/UKMPG(498): ContentProvider.onCreate called. Context: class android.app.Application

创建具有错误上下文的DB:

01-11 19:22:13.265: D/UKMPG(498): Creating DB instance with Context: class android.app.ApplicationContext

调用的init()方法对应于最后一次ContentProvider.onCreate()调用:

01-11 19:22:13.274: D/UKMPG(498): UKMPGDataProvider.init called. Context: class android.app.Application, db name :mpg_tracker.db

getWriteableDatabase()返回一个非测试数据库:

01-11 19:22:13.374: D/UKMPG(498): getWritableDatabase. Path of returned db: /data/data/barry.contentproviderexample/databases/mpg_tracker.db

由于’test’数据库不存在,无法删除下一个测试的数据库:

01-11 19:22:13.615: D/UKMPG(498): Database deleted:false

为了完整性,以下是在调试模式下运行时来自同一测试运行的logcat:

01-11 19:37:09.514: D/UKMPG(598): ContentProvider.onCreate called. Context: class android.app.Application
01-11 19:37:09.514: D/UKMPG(598): UKMPGDataProvider.init called. Context: class android.app.Application, db name :mpg_tracker.db
01-11 19:37:11.313: D/UKMPG(616): ContentProvider.onCreate called. Context: class android.app.Application
01-11 19:37:11.313: D/UKMPG(616): UKMPGDataProvider.init called. Context: class android.app.Application, db name :mpg_tracker.db

此时,ContentProder.onCreate已使用非测试上下文调用两次,但这发生在我的setUp()方法之前,因此它不会影响测试:

01-11 19:37:14.173: D/UKMPG(616): Initialising UKMPGDataProvider with test context: class android.test.RenamingDelegatingContext
01-11 19:37:14.173: D/UKMPG(616): UKMPGDataProvider.init called. Context: class android.test.RenamingDelegatingContext, db name :mpg_tracker.db
01-11 19:37:14.213: D/UKMPG(616): database null - going to create it
01-11 19:37:14.213: D/UKMPG(616): Creating DB instance with Context: class android.test.RenamingDelegatingContext
01-11 19:37:14.364: D/UKMPG(616): getWritableDatabase. Path of returned db: /data/data/barry.contentproviderexample/databases/test.mpg_tracker.db
01-11 19:37:14.794: D/UKMPG(616): Database deleted:true

任何人都可以帮我解决这个问题吗?我做错了什么,或者这是Android中的(线程?)错误?

它可以在设备上以及Android版本1.6到4.0中重复使用.

最佳答案 我想你应该在你的setUp()中调用setContext():

// warning: untested code
protected void setUp() throws Exception
{
    super.setUp();
    setContext(new RenamingDelegatingContext(getTargetContext(), "test.");

    ...
}

在这种情况下,您可能需要将基类更改为ProviderTestCase2.

点赞