使用 Robolectric 和 ORMLite 进行测试时使用模拟数据库

Use mock db when testing with Robolectric and ORMLite

我正在开发一个 Android 应用程序,它使用 OrmLiteSqliteOpenHelper 连接到 SQLite 数据库。

public class MyDatabaseHelper extends OrmLiteSqliteOpenHelper {
    ...

    private static final String DATABASE_NAME = "mydb.sqlite";
    private static MyDatabaseHelper helper = null;

    private MyDatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, BuildConfig.DATABASE_VERSION);
    }

    public static synchronized MyDatabaseHelper getHelper(Context context) {
        if (helper == null) {
            helper = new MyDatabaseHelper(context);
        }
        return helper;
    }
}

为了从数据库获取数据,我有一些提供程序 classes,他们使用一些 DAO。

public class ProductsProvider {

    public static List<Products> getProducts(Context context) {
        MyDatabaseHelper helper = MyDatabaseHelper.getHelper(context);
        Dao<Product, String> daoProducts = helperDatabase.getProductDao();
        ...
        ...
        ...
    }
}

我已经准备好 Robolectric 来测试我的代码,但我很难理解如何 Robolectric 与 ORMLite 一起使用。 我的想法是有一个模拟 database.sqlite,预先填充我通常拥有的相同结构和数据,并将其用于我的所有测试。例如,如果我想测试 ProductsProvider class,我应该这样做:

@RunWith(MyTestRunner.class)
public class ProductsProviderTest extends MyTestCase {

    @Test
    public void testDb() {
        List<Products> products = ProductsProvider.getProducts(getTestContext());
        assertNotNull(products);
        assertFalse(products.isEmpty());
    }
}

请注意 ProductsProvider.getProducts() 将使用 MyDatabaseHelper,它将使用 Android 应用程序标准位置的数据库,而不是我的本地文件。 如何修改我的测试代码以使用本地数据库作为 assetresource 添加测试,而不触及真正的代码应用程序?

这是我们的做法。

  1. 我们将示例数据库文件放在 src/test/res 文件夹中
  2. 我们运行数据库测试前的下一个代码:

    private void copyTestDatabase( String resourceDBName )
        throws URISyntaxException, IOException
    {
        String filePath = getClass().getResource( resourceDBName ).toURI().getPath();
    
        String destinationPath = new ContextWrapper( Robolectric.application.getApplicationContext() ).getDatabasePath(
            DatabaseHelper.DATABASE_NAME ).getAbsolutePath();
    
        Files.copy( new File( filePath ), new File( destinationPath ) );
    } 
    

要小心,因为这些测试超长

对于无法忍受 Robolectric 3 + Gradle 的 6-12 秒启动时间的任何人,以下适用于 Android 的内置 JUnit4 测试(DbHelper 扩展 OrmLiteSqliteOpenHelper)。

@RunWith(AndroidJUnit4.class)
public class DbTest {

    private DbHelper dbHelper;

    @Before
    public void setUp() throws Exception {
        Context context = new RenamingDelegatingContext(
                InstrumentationRegistry.getTargetContext(), "test_");
        dbHelper = new DbHelper(context);
    }
}

您可能可以进行许多优化,但我可以 运行 一个小的 I/O-heavy 套件,每次在 GenyMotion 上擦除数据库只需 2.5 秒。

如果您还没有跟上它的最新动态,我强烈建议您查看 Google 最近对其测试功能所做的工作。 The intro on the Robolectric site 在这一点上是一个彻头彻尾的谎言。