不同的sqlite数据库在android app中进行测试和实际使用

Posted

技术标签:

【中文标题】不同的sqlite数据库在android app中进行测试和实际使用【英文标题】:Different sqlite databases for testing and actual use in android app 【发布时间】:2015-02-26 08:24:03 【问题描述】:

免责声明 - 我已使用 GreenDAO ORM 在我的 android 应用程序中创建和管理 sqlite 数据库。

对于我的 android 应用程序,在编写单元测试时,我希望告诉应用程序切换到使用与正常数据库不同的某个数据库,以确保测试不会污染真实的数据库。相应地,我使用了适当的函数来创建新的数据库并像这样切换到它

public class DbTests extends ApplicationTestCase<MyApp> 
private static final String TAG = "DbTests";
private MyApp mApplication;
private Context mContext;

public DbTests() 
    super(MyApp.class);


@Override
protected void setUp() throws Exception 
    Log.d(TAG, "in setUp");
    super.setUp();
    createApplication();
    mApplication = getApplication();
    Log.d(TAG, "setUp done");


@Override
public void tearDown() throws Exception 
    super.tearDown();



private void setUpFreshInstallNoDataCase(boolean val) 
    assertNotNull(mApplication);
    LocalDataHelpers.setupLocalData(mApplication, InitialConditions.FreshInstallNoData);
    try 
        Thread.sleep(1000);
     catch (InterruptedException e) 
        e.printStackTrace();
    


public void testFreshInstallNoDataCase() 
    Log.d(TAG, "testFreshInstallNoDataCase");
    setUpFreshInstallNoDataCase(true);

    mContext = mApplication.getApplicationContext();
    assertEquals(0, PersonRepository.getAllPersons(mContext).size());





public class LocalDataHelpers 
public static final String TAG = "LocalDataHelpers";

static MyApp globalApplication;

public static void setupLocalData(MyApp app, String condition) 
    globalApplication = app;
    if(globalApplication.daoSession != null)
        Log.d(TAG, "daoSession not null");
        globalApplication.daoSession.clear();
        globalApplication.setupDatabase(condition);     
    


在我的应用中 onCreate 和 setupDatabase 是这样的

public void onCreate() 
    Log.d(TAG, "onCreate");
    super.onCreate();
    EventBus.getDefault().register(this);
    EventBus.getDefault().post(new PersonEvents.FetchPersonsFromServer());
    setupDatabase(InitialConditions.DefaultSetUp);


private void setupDatabase(String condition) 
    DaoMaster.DevOpenHelper helper = null;
    SQLiteDatabase db = null;
    DaoMaster daoMaster = null;
    if (condition.equals(InitialConditions.DefaultSetUp)) 
        helper = new DaoMaster.DevOpenHelper(this, "example-db", null);
        db = helper.getWritableDatabase();
        daoMaster = new DaoMaster(db);
    
    else if (condition.equals(InitialConditions.FreshInstallNoData)) 
        helper = new DaoMaster.DevOpenHelper(this, "freshInstallNoData-db", null);
        db = helper.getWritableDatabase();
        daoMaster = new DaoMaster(db);
        //clear all possible data here by dropping all tables and recreate
        Log.d(TAG, "Dropping all tables and recreating them");
        DaoMaster.dropAllTables(db, true);
        DaoMaster.createAllTables(db, false);
    
    if (helper != null && db != null && daoMaster != null) 
        daoSession.clear();
        daoSession = daoMaster.newSession();
    
    else 
        Log.e(TAG, "setupDatabase Error : condition " + condition + ", either helper or db or daomaster is null");
    
    List<Pair<String, String>> dbs = getDaoSession().getDatabase().getAttachedDbs();
    for (Pair<String, String> pair : dbs) 
        Log.d(TAG, "setupDatabase <" + pair.first + ", " + pair.second + ">");
    

FetchPersonsFromServer 的 onEvent 获取人员列表并使用 PersonDao 将他们保存到数据库中。

现在,如果我从我的设备中清除所有应用数据并直接运行测试,那么测试会按预期通过。但是,如果我正常运行应用程序,然后运行测试,断言语句在

处失败
assertEquals(0, PersonRepository.getAllPersons(mContext).size());

大小与默认 db 值相同。

我快要疯了,想找出原因。 setupDatabase 中的日志语句显示正确的数据库名称正在显示,即freshdbinstall-db ...

android 不允许有两个 dbs 吗?逻辑上应该没有问题吧?是GreenDao不允许吗?我是否犯了一些基本错误...

请帮忙。


编辑:Creating more than 1 *.db file with greenDao android ORM library 是否相关?

更新 1

我使用 adb shell、run-as cat /sdcard/debug/db 和 adb pull 在测试失败后查看默认数据库和新数据库

新数据库符合预期,没有 Person 条目,默认有 10 个条目。所以我猜问题出在断言/查询调用上......由于某种原因,它似乎正在使用默认数据库......查看存储库代码是

public static List<Person> getAllPersons(Context context) 
    return getPersonDao(context).loadAll();


private static PersonDao getPersonDao(Context c) 
    return ((MyApp) c.getApplicationContext()).getDaoSession().getPersonDao();

据此看来会话没有被更新,前一个会话仍在使用中

【问题讨论】:

【参考方案1】:

如果您可以选择Robolectric,这就是我们使用内存 SQLite 数据库和填充测试数据的方式:

TestApplication.java

public class TestApplication extends YourApplication
    implements TestLifecycleApplication 

    @Override
    public void onCreate() 
        super.onCreate();
        YourProvider provider = new YourProvider(YOUR_CONTENT_AUTHORITY);
        provider.onCreate();
        ShadowContentResolver.registerProvider(YOUR_CONTENT_AUTHORITY, provider);
    
    ...

SomeTest.java

@RunWith(RobolectricTestRunner.class)
public class SomeTest 
    @Test
    public void testSQLite() 
        // insert test data into in-memory SQLite
        ShadowContentResolver resolver = shadowOf(Robolectric.getShadowApplication().getContentResolver());
        ContentValues cv = new ContentValues();
        cv.put("column_name", "column_value");
        resolver.insert(YOUR_CONTENT_URI, cv);
        // test against in-memory SQLite
        ...
    
    ...

对不起,我忘记了我阅读这篇文章的文章来源。

【讨论】:

以上是关于不同的sqlite数据库在android app中进行测试和实际使用的主要内容,如果未能解决你的问题,请参考以下文章

SQLite - 跨数据库查询不起作用

关于SQLite在Android开发中的知识点总结

安卓怎么从数据库调取数据在界面上显示出来?有几种方法啊?

Ionic - 在 android 的不同目录中创建 SQLite 数据库

Android Studio App开发中数据库SQLite的解析及实战使用(包括创建数据库,增删改查,记住密码等 附源码必看)

Android开发系列之SQLite