SQLite 现有数据库单元测试错误使用 robolectric [英] SQLite existing database unit testing error using robolectric

查看:74
本文介绍了SQLite 现有数据库单元测试错误使用 robolectric的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用程序中,我将 SQLite 数据库放入资产文件夹.我在我的应用程序中成功使用了它,但现在我想测试数据库提供者"类中的方法,该类具有多种 CRUD 操作方法.我尝试跟进本教程 https://medium.com/@elye.project/android-sqlite-database-unit-testing-is-easy-a09994701162 但我的测试类失败并出现异常

In my app, I have the SQLite database which I have put into assets folder. I successfully use it in my app, but now I want to test methods in database "provider" class which has several methods for CRUD operations. I tried to follow up this tutorial https://medium.com/@elye.project/android-sqlite-database-unit-testing-is-easy-a09994701162 but my test class fails with the exception

android.database.sqlite.SQLiteException: Cannot open SQLite connection, base error code: 14

at org.robolectric.shadows.ShadowSQLiteConnection.rethrow(ShadowSQLiteConnection.java:56)
at org.robolectric.shadows.ShadowSQLiteConnection.access$500(ShadowSQLiteConnection.java:33)
at org.robolectric.shadows.ShadowSQLiteConnection$Connections.execute(ShadowSQLiteConnection.java:466)
at org.robolectric.shadows.ShadowSQLiteConnection$Connections.open(ShadowSQLiteConnection.java:353)
at org.robolectric.shadows.ShadowSQLiteConnection.nativeOpen(ShadowSQLiteConnection.java:61)
at android.database.sqlite.SQLiteConnection.nativeOpen(SQLiteConnection.java)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:209)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:806)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:791)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:669)
at com.education.frogtravel.ege4task.database.DBHelper.openDataBase(DBHelper.java:78)
at com.education.frogtravel.ege4task.database.DBProvider.<init>(DBProvider.kt:22)
at com.education.frogtravel.ege4task.database.DBProviderTest.setup(DBProviderTest.kt:23)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:251)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
at com.intellij.rt.execution.application.AppMainV2.main(AppMainV2.java:131)

Caused by: com.almworks.sqlite4java.SQLiteException: [14] unable to open database file
at com.almworks.sqlite4java.SQLiteConnection.open0(SQLiteConnection.java:1353)
at com.almworks.sqlite4java.SQLiteConnection.open(SQLiteConnection.java:258)
at com.almworks.sqlite4java.SQLiteConnection.open(SQLiteConnection.java:269)
at org.robolectric.shadows.ShadowSQLiteConnection$Connections$1.call(ShadowSQLiteConnection.java:360)
at org.robolectric.shadows.ShadowSQLiteConnection$Connections$1.call(ShadowSQLiteConnection.java:353)
at org.robolectric.shadows.ShadowSQLiteConnection$Connections$6.call(ShadowSQLiteConnection.java:452)
at org.robolectric.shadows.ShadowSQLiteConnection$Connections$6.call(ShadowSQLiteConnection.java:446)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

方法失败

 public void openDataBase() throws SQLException {

    //Open the database
    String myPath = DB_PATH + DBScheme.DB_NAME;
    myDatabase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

}

符合openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

我的整个 SQLiteOpenHelper 类

My whole SQLiteOpenHelper class

import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class DBHelper extends SQLiteOpenHelper {
    private static String DB_PATH = "/data/data/my.package.path/databases/";
    private SQLiteDatabase myDatabase;
private final Context context;


public DBHelper(Context context) {
    super(context, DBScheme.DB_NAME, null, 1);
    this.context = context;
}

public void createDatabase() throws IOException{
    boolean dbExist = checkDataBase();

    if(!dbExist){//If database doesn't exist
        this.getReadableDatabase();

        try{
            copyDatabase();
        }catch(IOException e){
            throw new Error("Error copying database");
        }
    }
}


private boolean checkDataBase() {
    SQLiteDatabase checkDB = null;

    try{
        String myPath = DB_PATH + DBScheme.DB_NAME;
        checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
    }catch (SQLiteException e){
        //Database doesn't exist
    }

    return checkDB != null;
}

private void copyDatabase() throws IOException{
    InputStream inputStream = context.getAssets().open(DBScheme.DB_NAME);
    String outFileName = DB_PATH + DBScheme.DB_NAME;
    OutputStream outputStream = new FileOutputStream(outFileName);

    byte[] buffer = new byte[1024];
    int length;
    while((length = inputStream.read(buffer)) > 0){
        outputStream.write(buffer, 0, length);
    }

    outputStream.flush();
    outputStream.close();
    inputStream.close();
}

public void openDataBase() throws SQLException {

    //Open the database
    String myPath = DB_PATH + DBScheme.DB_NAME;
    myDatabase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

}

@Override
public synchronized void close() {

    if(myDatabase != null)
        myDatabase.close();

    super.close();

}


@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {

}

@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

}

}

我的测试班

@RunWith(RobolectricGradleTestRunner::class)
@Config(constants = BuildConfig::class, sdk = intArrayOf(LOLLIPOP), packageName = "my.pachage.path.database")

class DBProviderTest {
    lateinit var dbHelper: DBProvider

    @Before
    fun setup() {
        dbHelper = DBProvider(RuntimeEnvironment.application)
        dbHelper.clearStatistics()
    }

//commented to test because crashed in this line before
//    @After
//    fun tearDown(){
//        dbHelper.clearStatistics()
//    }

    @Test
    fun testDBUpdate(){
        dbHelper = DBProvider(RuntimeEnvironment.application)

        val wordId = 1
        val isRight = true

        dbHelper.updateWordStatistics(wordId, isRight)

        assertEquals(dbHelper.getStatisticsForWord(wordId), Statistics(wordId, 1, 1))
    }
}

DBHelper 使用 Java,测试类使用 Kotlin.我想这是因为我不会在旅途中制作数据库,而是使用已经存在的数据库.我可以为测试目的编写额外的逻辑,但据我所知,为了测试而改变应用程序的逻辑是错误的.所以我的问题是如何测试未创建但只是从 android assets 文件夹中打开的 DB.\?

DBHelper is in Java and testing class is in Kotlin. I guess this happens because I don't make the DB on the go, but use already existing one. I can write additional logic for testing purposes, but as I understood it will be wrong, to change the logic of application just for testing. So my question is how to test DB which is not created but simply opened from android assets folder.\?

推荐答案

很高兴看到整个文件 项目很大所以需要把它放在 ONE Drive 或 Google Drive 这个应用程序在 FLY 上创建 SQLite 数据库它也创建了动态桌子

Happy to sip the whole file up project is big so need to put it on ONE Drive or Google Drive This app creates SQLite Databases on the FLY it also creates the tables on the fly

public class ManageTables extends AppCompatActivity {

Button btnMakeTable;
Button btnAddTableData;
Button btnToDetails;
Button btnDelete;
EditText etQuizTable;
EditText etTableDes;

public static String strIDT;
public static String NEW_TABLE ;

DBHelper dbHelper = new DBHelper(this);
public SQLiteDatabase db;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_manage_tables);

    setRequestedOrientation( ActivityInfo.SCREEN_ORIENTATION_PORTRAIT );
    this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);

    btnMakeTable = findViewById(R.id.btnMakeTable);
    btnAddTableData = findViewById(R.id.btnAddTableData);
    btnToDetails = findViewById(R.id.btnToDetails);
    btnDelete = findViewById(R.id.btnDelete);
    etQuizTable = findViewById(R.id.etQuizTable);
    etTableDes = findViewById(R.id.etTableDes);

    // Brig values over from ManageTablesListView
    etQuizTable.setText(MT_QUIZ_TABLE);
    etTableDes.setText(MT_QUIZ_NAME);

}// END onCreate

public void makeTABLE(View view){
    if(etQuizTable.getText().length() < 5 || etQuizTable.getText().length() >14){
        Toast.makeText(getApplicationContext(), "Quiz Name Max Length is 14 Characters\n"
                +"\nQuiz Name Min Length is 5 Characters", Toast.LENGTH_LONG ).show();
        return;
    }

    String tstr = "^(?!.*\\s)^(?!.*\\W)^(?!.*\\d)([a-zA-Z])";
    String astr = etQuizTable.getText().toString().trim();
    Pattern regex = Pattern.compile(tstr);
    Matcher regexMatcher = regex.matcher(astr);

    boolean foundMatch = regexMatcher.find();

    if(foundMatch == false){

        Toast.makeText( getApplicationContext(),"Upper & Lower Case Letters ONLY\n"
                + "\nNO - Numbers in Quiz Name\n"
                + "\nNO - Special Character in Quiz Name\n"
                +"\nNO - Spaces in the Quiz Name", Toast.LENGTH_LONG ).show();
        etQuizTable.requestFocus();

        return ;
    }

    // Make Table Button
    if(etQuizTable.getText().toString().isEmpty()){
        Toast.makeText(getApplicationContext(), "Enter Quiz Name", Toast.LENGTH_LONG ).show();
        etQuizTable.requestFocus();
        return;
    }
    if(etTableDes.getText().toString().isEmpty()){
        Toast.makeText(getApplicationContext(), "Enter Quiz Description", Toast.LENGTH_LONG ).show();
        etTableDes.requestFocus();
        return;
    }

    if(etTableDes.getText().length() < 5 || etTableDes.getText().length() >26){
        Toast.makeText(getApplicationContext(), "Description Max Length is 26 Characters\n"
                +"\nDescription Min Length is 5 Characters", Toast.LENGTH_LONG ).show();
        return;
    }

    NEW_TABLE = etQuizTable.getText().toString().trim();

    db = dbHelper.getWritableDatabase();
    ArrayList<String> arrTblNames = new ArrayList<>();
    Cursor c = db.rawQuery("SELECT name FROM sqlite_master WHERE type='table'", null);

    if (c.moveToFirst()) {
        while ( !c.isAfterLast() ) {
            arrTblNames.add( c.getString( c.getColumnIndex("name")) );
            c.moveToNext();
        }
    }
    c.close();
    db.close();

    for(int i=0;i<arrTblNames.size();i++) {
        if(arrTblNames.get(i).equals(NEW_TABLE)) {
            Toast.makeText(getApplicationContext(), "That Quiz Exists\n\n"
                    +"Choose a New Quiz Name", Toast.LENGTH_LONG ).show();
            etQuizTable.requestFocus();
            return;
        }
    }

    String tablename = NEW_TABLE;
    String tabledes = etTableDes.getText().toString().trim();
    dbHelper.insertIntoTABLE_TRACKER(tablename,tabledes);

    // Create NEW_TABLE and show Toast Message
    // First check for duplicate NEW_TABLE name ABOVE
    NEW_TABLE = etQuizTable.getText().toString().trim();

    dbHelper.onCreateNewTable();
    Toast.makeText(getApplicationContext(), "Quiz Created NOW\n\n"
            +"Add the First Question", Toast.LENGTH_LONG ).show();
    Intent intent = new Intent(ManageTables.this, TableCreate.class );
    startActivity( intent );
}

public void addTABLEDATA(View view){

    chkENTRY();

    // add NEW_TABLE data (records) questions and answers
    if(etQuizTable.getText().toString().equals("")){
        Toast.makeText(getApplicationContext(), "Enter Quiz Name\n\n"
                +"           OR"+"\n\nCreate Quiz First", Toast.LENGTH_LONG ).show();
        etQuizTable.requestFocus();
        return;
    }

    NEW_TABLE = etQuizTable.getText().toString().trim();

    db = dbHelper.getWritableDatabase();
    ArrayList<String> arrTblNames = new ArrayList<>();
    Cursor c = db.rawQuery("SELECT name FROM sqlite_master WHERE type='table'", null);

    if (c.moveToFirst()) {
        while ( !c.isAfterLast() ) {
            arrTblNames.add( c.getString( c.getColumnIndex("name")) );
            c.moveToNext();
        }
    }
    c.close();
    db.close();


    boolean matchFound = false;
    for(int i=0;i<arrTblNames.size();i++) {
        if(arrTblNames.get(i).equals(NEW_TABLE)) {
            Intent intent = new Intent(ManageTables.this, TableCreate.class );
            startActivity( intent );
            matchFound = true;
        }
    }
    if (!matchFound) {
        Toast.makeText(getApplicationContext(), "No Such Quiz\n\n"
                +"           OR"+"\n\nCreate Quiz First", Toast.LENGTH_LONG ).show();
        etQuizTable.requestFocus();
    }
}

public void toDetails(View view){

    chkENTRY();

    // show detail view
    if(etQuizTable.getText().toString().equals("")) {
        Toast.makeText(getApplicationContext(), "Enter Quiz Name\n\n"
                + "           OR" + "\n\nCreate Quiz First", Toast.LENGTH_LONG).show();
        etQuizTable.requestFocus();
        return;
    }

    NEW_TABLE = etQuizTable.getText().toString().trim();

    db = dbHelper.getWritableDatabase();
    ArrayList<String> arrTblNames = new ArrayList<>();
    Cursor c = db.rawQuery("SELECT name FROM sqlite_master WHERE type='table'", null);

    if (c.moveToFirst()) {
        while ( !c.isAfterLast() ) {
            arrTblNames.add( c.getString( c.getColumnIndex("name")) );
            c.moveToNext();
        }
        c.close();
        db.close();
    }

    boolean matchFound = false;
    for(int i=0;i<arrTblNames.size();i++) {

        if (arrTblNames.get(i).equals(NEW_TABLE)) {
            Intent intent = new Intent(ManageTables.this, DetailsActivity.class );
            startActivity( intent );
            matchFound = true;
        }
    }
    if (!matchFound) {
        Toast.makeText(getApplicationContext(), "No Such Quiz\n\n"
                +"           OR"+"\n\nCreate Quiz First", Toast.LENGTH_LONG ).show();
        etQuizTable.requestFocus();
    }
}

// this is btnDelete
public void onDELETE(View view) {

    if(etQuizTable.length() == 0){
        Toast.makeText(getApplicationContext(), "Enter Quiz Name", Toast.LENGTH_SHORT).show();
        return;
    }
    callDIALOG();
}

private void callDIALOG(){

    final Dialog openDialog = new Dialog(this);
    openDialog.setContentView(R.layout.delete_dialog);
    TextView tvDDT = openDialog.findViewById(R.id.tvDDT);
    tvDDT.setText("Your DELETING "+etQuizTable.getText().toString().trim());
    Button btnYES = openDialog.findViewById(R.id.btnYES);
    Button btnNO = openDialog.findViewById(R.id.btnNO);
    openDialog.setCancelable(false);

    btnYES.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            NEW_TABLE = etQuizTable.getText().toString().trim();

            db = dbHelper.getWritableDatabase();
            ArrayList<String> arrTblNames = new ArrayList<>();
            Cursor c = db.rawQuery("SELECT name FROM sqlite_master WHERE type='table'", null);

            if (c.moveToFirst()) {
                while ( !c.isAfterLast() ) {
                    arrTblNames.add( c.getString( c.getColumnIndex("name")) );
                    c.moveToNext();
                }
                c.close();
                db.close();
            }

            boolean matchFound = false;
            for(int i=0;i<arrTblNames.size();i++) {

                if (arrTblNames.get(i).equals(NEW_TABLE)) {
                    Intent intent = new Intent(ManageTables.this, DetailsActivity.class );
                    startActivity( intent );
                    matchFound = true;
                }
            }
            if (!matchFound) {
                Toast.makeText(getApplicationContext(), "NO MATCH\n\n"
                        +"CLICK NO AND"+"\n\nCHECK QUIZ NAME", Toast.LENGTH_LONG ).show();
                etQuizTable.requestFocus();
                return;
            }

            //chkENTRY(null);
            // THIS method deletes the TABLE NAME from TABLE_TRACKER
            // THEN DROPS the corresponding CREATED TABLE from the DB
            // doDrop makes 4 calls to DBHelper
            dbHelper.deleteFROM_TABLE_RESPONSE();
            strIDT = dbHelper.getCol_IDT();
            dbHelper.deleteTABLE_FROM_TABLE_TRACKER();

            dbHelper.dropTABLE();
            Intent intent = new Intent(ManageTables.this,ManageTablesListView.class);
            startActivity(intent);

            Toast.makeText(getApplicationContext(), "Quiz Data Deleted ", Toast.LENGTH_SHORT).show();
            openDialog.dismiss();
        }
    });
    btnNO.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            openDialog.dismiss();
        }
    });
    openDialog.show();
}

public void chkENTRY(){

    String tstr = "^(?!.*\\s)^(?!.*\\W)^(?!.*\\d)([a-zA-Z])";
    String astr = etQuizTable.getText().toString().trim();
    Pattern regex = Pattern.compile(tstr);
    Matcher regexMatcher = regex.matcher(astr);

    boolean foundMatch = regexMatcher.find();

    if(foundMatch == false){

        Toast.makeText( getApplicationContext(),"Upper & Lower Case Letters ONLY\n"
                + "\nNO - Numbers in Quiz Name\n"
                + "\nNO - Special Character in Quiz Name\n"
                +"\nNO - Spaces in the Quiz Name", Toast.LENGTH_LONG ).show();
        etQuizTable.requestFocus();

        return ;
    }
}

public void onBackPressed() {
    Intent intent = new Intent(ManageTables.this,ManageTablesListView.class);
    startActivity(intent);
}

}

这篇关于SQLite 现有数据库单元测试错误使用 robolectric的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆