如何使用Roboelectric和Fest测试具有原生二进制文件的Android应用程序?(How use Roboelectric and Fest to test an android app w

编程入门 行业动态 更新时间:2024-10-24 20:15:11
如何使用Roboelectric和Fest测试具有原生二进制文件的Android应用程序?(How use Roboelectric and Fest to test an android app with native binaries?)

我正试图在我自己的项目中设置roboelectric和fest。 但是,当我尝试在命令行中运行./gradlew clean test时,我在测试报告中遇到以下错误:

http://pastebin.com/5gaJgftf

我的项目确实构建了应用程序没有错误。 当我尝试运行测试时,我只得到这个问题,所以看起来Roboelectric不知道我不知道我的原生sqlcipher二进制文件和其他二进制文件。

所以我尝试用加载了必要二进制文件的运行器的阴影类加载它:

@Config(emulateSdk = 18, shadows={MyJniClass.class}) @RunWith(RobolectricTestRunner.class) public class MainActivityBuildTest { @Test public void testSomething() throws Exception { Activity activity = Robolectric.buildActivity(MainActivity.class).create().get(); assertTrue(activity != null); } }

使用我的自定义jniloader影子类

@Implements(RobolectricTestRunner.class) class MyJniClass { static { try { System.loadLibrary("libdatabase_sqlcipher"); System.loadLibrary("libdatabase_android"); System.loadLibrary("libstlport_shared"); } catch (UnsatisfiedLinkError e) { // only ignore exception in non-android env if ("Dalvik".equals(System.getProperty("java.vm.name"))) throw e; } } }

I'm trying to setup roboelectric and fest in my own project. However when I try to run ./gradlew clean test in the command line I get the following errors in the test report:

http://pastebin.com/5gaJgftf

My project does build the app without errors though. I only get this issue when I try to run tests, so it seems that Roboelectric is not aware is not aware of my native sqlcipher binaries and other binaries.

So I tried loading it with a shadow class for the runner that loads up the necessary binaries:

@Config(emulateSdk = 18, shadows={MyJniClass.class}) @RunWith(RobolectricTestRunner.class) public class MainActivityBuildTest { @Test public void testSomething() throws Exception { Activity activity = Robolectric.buildActivity(MainActivity.class).create().get(); assertTrue(activity != null); } }

Using my custom jniloader shadow class

@Implements(RobolectricTestRunner.class) class MyJniClass { static { try { System.loadLibrary("libdatabase_sqlcipher"); System.loadLibrary("libdatabase_android"); System.loadLibrary("libstlport_shared"); } catch (UnsatisfiedLinkError e) { // only ignore exception in non-android env if ("Dalvik".equals(System.getProperty("java.vm.name"))) throw e; } } }

最满意答案

你有问题使用sql密码与robolectric?

我的解决方法是使用两个不同的SQLiteOpenHelper实现。 一个使用sqlcipher,另一个使用默认数据库实现。 这两个都在工厂类后面,它基于静态布尔标志创建SQLiteDatabase,因此将从progard中消除不安全的数据库处理。

下一个问题是两者都有不同的SQLiteDatabase类。 因此,再次构建一个SQLiteDatabase的包装器,它将使用SQLiteOpenHelper Wrapper中正确的SQLiteDatabase创建。 以Cipher变体为基础。 您可以忽略默认SQLiteDatabase中存在但不存在于密码变体中的方法。 此包装类使用相同的静态布尔标志来选择应使用的数据库。 如果犯了一个错误,并采取错误的数据库,那么它应该抛出一个空指针异常;)

在您的应用程序代码中,您现在应该只使用包装类。

DatabaseHelper包装器的示例

public class MyDatabaseHelper { public static final String DATABASE_NAME = "my.db"; public static final int DATABASE_VERSION = 1; MyEncryptedDatabaseHelper encryptedDatabase; MyUnsecureDatabaseHelper unsecureDatabase; public MyDatabaseHelper(Context context) { if (ReleaseControl.USE_UNSECURE_DATABASE) { unsecureDatabase = new MyUnsecureDatabaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION); return; } encryptedDatabase = new MyEncryptedDatabaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION); } public MySQLiteDatabase getWritableDatabase(String password) throws MySQLiteException { if (ReleaseControl.USE_UNSECURE_DATABASE) { try { return new MySQLiteDatabase(unsecureDatabase.getWritableDatabase()); } catch (android.database.SQLException e) { throw new MySQLiteException(e); } } try { return new MySQLiteDatabase(encryptedDatabase.getWritableDatabase(password)); } catch (net.sqlcipher.database.SQLiteException e) { throw new MySQLiteException(e); } } }

来自SQLiteDatabase包装器的简短片段

public class MySQLiteDatabase { private net.sqlcipher.database.SQLiteDatabase encryptedDatabase; private android.database.sqlite.SQLiteDatabase unsecureDatabase; public MySQLiteDatabase(SQLiteDatabase database) { encryptedDatabase = database; } public MySQLiteDatabase(android.database.sqlite.SQLiteDatabase database) { unsecureDatabase = database; } public static void loadLibs(android.content.Context context) { if (ReleaseControl.USE_UNSECURE_DATABASE) { return; } SQLiteDatabase.loadLibs(context); } public static int releaseMemory() { if (ReleaseControl.USE_UNSECURE_DATABASE) { return android.database.sqlite.SQLiteDatabase.releaseMemory(); } return net.sqlcipher.database.SQLiteDatabase.releaseMemory(); } public static SQLiteDatabase openDatabase(String path, String password, MyCursorFactory factory, int flags) { if(factory == null) factory = new NullCursorFactory(); if (ReleaseControl.USE_UNSECURE_DATABASE) { return new MySQLiteDatabase(android.database.sqlite.SQLiteDatabase.openDatabase(path, factory.getUnsecure(), flags)); } return new MySQLiteDatabase(net.sqlcipher.database.SQLiteDatabase.openDatabase(path, password, factory.getEncrypted(), flags)); }

在robolectric测试中,我将每次反射的USE_UNSECURE_DATABASE设置为true

You have issues to use sql cipher with robolectric?

My workaround is to use two different implementation of the SQLiteOpenHelper. One use sqlcipher and the another one the default database implementation. This both are behind a factory class, which create the SQLiteDatabase based on a static boolean flag, so the unscure database handling will be eliminated from progard.

The next issue is that both have different SQLiteDatabase classes. So again build a wrapper around the SQLiteDatabase which will be created with the right SQLiteDatabase from the SQLiteOpenHelper Wrapper. Take the Cipher variant as your base. you can ignore methods which exist at default SQLiteDatabase but not at the cipher variant. This wrapper class take the same static boolean flag to choose which database should be used. if make a mistake and take the wrong database then it should throw a null pointer exception ;)

in your app code you should now use only the wrapper classes.

example for DatabaseHelper wrapper

public class MyDatabaseHelper { public static final String DATABASE_NAME = "my.db"; public static final int DATABASE_VERSION = 1; MyEncryptedDatabaseHelper encryptedDatabase; MyUnsecureDatabaseHelper unsecureDatabase; public MyDatabaseHelper(Context context) { if (ReleaseControl.USE_UNSECURE_DATABASE) { unsecureDatabase = new MyUnsecureDatabaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION); return; } encryptedDatabase = new MyEncryptedDatabaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION); } public MySQLiteDatabase getWritableDatabase(String password) throws MySQLiteException { if (ReleaseControl.USE_UNSECURE_DATABASE) { try { return new MySQLiteDatabase(unsecureDatabase.getWritableDatabase()); } catch (android.database.SQLException e) { throw new MySQLiteException(e); } } try { return new MySQLiteDatabase(encryptedDatabase.getWritableDatabase(password)); } catch (net.sqlcipher.database.SQLiteException e) { throw new MySQLiteException(e); } } }

and short snippet from SQLiteDatabase wrapper

public class MySQLiteDatabase { private net.sqlcipher.database.SQLiteDatabase encryptedDatabase; private android.database.sqlite.SQLiteDatabase unsecureDatabase; public MySQLiteDatabase(SQLiteDatabase database) { encryptedDatabase = database; } public MySQLiteDatabase(android.database.sqlite.SQLiteDatabase database) { unsecureDatabase = database; } public static void loadLibs(android.content.Context context) { if (ReleaseControl.USE_UNSECURE_DATABASE) { return; } SQLiteDatabase.loadLibs(context); } public static int releaseMemory() { if (ReleaseControl.USE_UNSECURE_DATABASE) { return android.database.sqlite.SQLiteDatabase.releaseMemory(); } return net.sqlcipher.database.SQLiteDatabase.releaseMemory(); } public static SQLiteDatabase openDatabase(String path, String password, MyCursorFactory factory, int flags) { if(factory == null) factory = new NullCursorFactory(); if (ReleaseControl.USE_UNSECURE_DATABASE) { return new MySQLiteDatabase(android.database.sqlite.SQLiteDatabase.openDatabase(path, factory.getUnsecure(), flags)); } return new MySQLiteDatabase(net.sqlcipher.database.SQLiteDatabase.openDatabase(path, password, factory.getEncrypted(), flags)); }

In robolectric test i set the USE_UNSECURE_DATABASE per reflection true

更多推荐

本文发布于:2023-08-05 21:51:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1441455.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:如何使用   应用程序   二进制文件   测试   Fest

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!