3

私は自分のプロジェクトでロボエレクトリックとフェストをセットアップしようとしています。ただし、コマンド ラインで ./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;
        }
    }
}
4

1 に答える 1

4

Robolectric で SQL 暗号を使用する際に問題がありますか?

私の回避策は、SQLiteOpenHelper の 2 つの異なる実装を使用することです。1 つは sqlcipher を使用し、もう 1 つはデフォルトのデータベース実装を使用します。これは両方とも、静的なブール値フラグに基づいて SQLiteDatabase を作成するファクトリ クラスの背後にあるため、不確かなデータベース処理は progard から排除されます。

次の問題は、両方が異なる SQLiteDatabase クラスを持っていることです。したがって、SQLiteOpenHelper ラッパーから適切な SQLiteDatabase を使用して作成される 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 に設定しました

于 2014-08-06T07:09:32.490 に答える