简体   繁体   English

如何使用Roboelectric和Fest测试带有原生二进制文件的Android应用程序?

[英]How use Roboelectric and Fest to test an android app with native binaries?

I'm trying to setup roboelectric and fest in my own project. 我正试图在我自己的项目中设置roboelectric和fest。 However when I try to run ./gradlew clean test in the command line I get the following errors in the test report: 但是,当我尝试在命令行中运行./gradlew clean test时,我在测试报告中收到以下错误:

http://pastebin.com/5gaJgftf 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. 我只是在尝试运行测试时才遇到这个问题,所以Roboelectric似乎并不知道我的本机sqlcipher二进制文件和其他二进制文件。

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 使用我的自定义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;
        }
    }
}

You have issues to use sql cipher with robolectric? 你有问题使用sql密码与robolectric?

My workaround is to use two different implementation of the SQLiteOpenHelper. 我的解决方法是使用两个不同的SQLiteOpenHelper实现。 One use sqlcipher and the another one the default database implementation. 一个使用sqlcipher,另一个使用默认数据库实现。 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. 这两者都在工厂类后面,它基于静态布尔标志创建SQLiteDatabase,因此将从progard中消除不安全的数据库处理。

The next issue is that both have different SQLiteDatabase classes. 下一个问题是两者都有不同的SQLiteDatabase类。 So again build a wrapper around the SQLiteDatabase which will be created with the right SQLiteDatabase from the SQLiteOpenHelper Wrapper. 因此,再次围绕SQLiteDatabase构建一个包装器,它将使用SQLiteOpenHelper Wrapper中正确的SQLiteDatabase创建。 Take the Cipher variant as your base. 以Cipher变体为基础。 you can ignore methods which exist at default SQLiteDatabase but not at the cipher variant. 您可以忽略默认SQLiteDatabase中存在但不存在密码变体的方法。 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 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);
    }
}
}

and short snippet from SQLiteDatabase wrapper 来自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));
}

In robolectric test i set the USE_UNSECURE_DATABASE per reflection true 在robolectric测试中,我将每次反射的USE_UNSECURE_DATABASE设置为true

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM