使用ContentProviders进行Android单元测试

时间:2012-01-11 19:45:27

标签: android multithreading unit-testing android-contentprovider

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

该应用程序工作正常,但我的测试在eclipse上以“运行”模式运行时偶尔会失败 - 它们会以“调试”模式传递。在我的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

使用错误的上下文创建数据库:

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上重复。

1 个答案:

答案 0 :(得分:2)

我认为你应该在setUp()中调用setContext():

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

    ...
}

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