我已经在一些类(使用模式DAO)中使用android.database包中的SQLiteOpenHelper实现了对数据库的访问.

我使用AndroidTestCase为这些类编写了一些junit测试,但这会导致测试使用与应用程序相同的数据库.

我读到ProviderTestCase2RenamingDelegatingContext可以分别用于测试数据库.不幸的是,我找不到任何演示如何使用ProviderTestCase2/RenamingDelegatingContext测试数据库的教程/示例.

有没有人可以给我指个方向,或者给我一些提示,或者分享一些数据库测试的代码?!

cheese !!

推荐答案

如果在其上下文中打开数据库之前已经存在一个数据库,则ProviderTestCaseRenamingDelegatingContext都将销毁该数据库,因此从这个意义上说,它们在打开SQLite数据库方面都有相同的低级方法.

您可以通过在setUp()中打开装置中的数据库来利用这一点,这将确保您在每个测试用例之前使用新的数据库.

我建议您编写内容提供程序,而不是创建数据库适配器.您可以使用一个公共接口来访问数据,无论它是存储在数据库中还是网络上的某个地方,内容提供者的设计都可以方便地访问此类数据,但要付出一些IPC开销的代价,这是我们大多数人不应该关心的.

如果您这样做是为了访问SQLite数据库,那么框架将在单独的过程中为您完全管理数据库连接.作为补充,ProviderTestCase2<ContentProvider>完全 bootstrap 了内容Provider 的测试上下文,而无需编写一行代码.

但是,这并不是说自己做 bootstrap 不是一项巨大的努力.因此,假设您有一个这样的数据库适配器;我们只关注open()个用于获得对数据库的写访问权限的适配器,没什么特别的:

public class MyAdapter {

    private static final String DATABASE_NAME = "my.db";
    private static final String DATABASE_TABLE = "table";
    private static final int DATABASE_VERSION = 1;


    /**
     * Database queries
     */
    private static final String DATABASE_CREATE_STATEMENT = "some awesome create statement";

    private final Context mCtx;
    private SQLiteDatabase mDb;
    private DatabaseHelper mDbHelper;

    private static class DatabaseHelper extends SQLiteOpenHelper {

        public DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL(DATABASE_CREATE_STATEMENT);  
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int a, int b) {
            // here to enable this code to compile
        }
    }

    /**
     * Constructor - takes the provided context to allow for the database to be
     * opened/created.
     * 
     * @param context the Context within which to work.
     */
    public MyAdapter(Context context) {
        mCtx = context;
    }

    /**
        * Open the last.fm database. If it cannot be opened, try to create a new
        * instance of the database. If it cannot be created, throw an exception to
        * signal the failure.
        * 
        * @return this (self reference, allowing this to be chained in an
        *         initialization call)
        * @throws SQLException if the database could be neither opened or created
        */
    public MyAdapter open() throws SQLException {
        mDbHelper = new DatabaseHelper(mCtx);
        mDb = mDbHelper.getWritableDatabase();
        return this;
    }

    public void close() {
            mDbHelper.close();
        }

}

然后,您可以这样编写您的测试:

public final class MyAdapterTests extends AndroidTestCase {

    private static final String TEST_FILE_PREFIX = "test_";
private MyAdapter mMyAdapter;

@Override
protected void setUp() throws Exception {
    super.setUp();

    RenamingDelegatingContext context 
        = new RenamingDelegatingContext(getContext(), TEST_FILE_PREFIX);

    mMyAdapter = new MyAdapter(context);
    mMyAdapter.open();
}

@Override
protected void tearDown() throws Exception {
    super.tearDown();

    mMyAdapter.close();
    mMyAdapter = null;
}

public void testPreConditions() {
    assertNotNull(mMyAdapter);
}

}

因此,这里发生的情况是,一旦调用MyAdapter(context).open(),RenamingDelegatingContext的上下文实现将始终重新创建数据库.在调用MyAdapter.DATABASE_CREATE_STATEMENT之后,您现在编写的每个测试都将与数据库的状态相冲突.

Database相关问答推荐

如何将对象源动态设置为子窗体

如何将使用模块创建的 Redis RDB 文件迁移到没有该模块的部署? (RedisStack 版本 7.2+ 中不再包含 RedisGraph)

使用自动递增主键将 csv 导入 sqlite

为什么引用 SQLite rowid 会导致外键不匹配?

什么技术对处理数百万条记录最有效?

递归关系的数据库设计

存储过程的缺点

微服务:每个实例或每个微服务的数据源?

区分大小写的数据库有什么好处吗?

无法在 MYSQL 5.5 w/MYSQL Workbench 中更改模式名称

PHP 和 MySQL Select 单个值

谁有维基数据库?

一个 Linq to Sql - 多个 .DBML 文件或一个 .DBML 文件

使用 PHP 和 MySQL 开发测验Web 应用程序的数据库设计

App=EntityFramework 在 Sql 连接字符串中有什么作用?

如何使用反射调用扫描可变参数函数

ManyToOneRel 和 ForeignKey 的区别?

在一个查询中使用 group by 计算多列

Rails 控制台 - 查找在某天创建的位置

如何知道mongodb使用的是哪个存储引擎?