我一直在努力解决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上重复。
答案 0 :(得分:2)
我认为你应该在setUp()中调用setContext():
// warning: untested code
protected void setUp() throws Exception
{
super.setUp();
setContext(new RenamingDelegatingContext(getTargetContext(), "test.");
...
}
在这种情况下,您可能需要将基类更改为ProviderTestCase2。