在我的应用程序中,我有一个SQLite数据库,该数据库已放入资产文件夹中。我已在我的应用程序中成功使用它,但是现在我想在数据库“ provider”类中测试方法,该类具有几种用于CRUD操作的方法。我试图继续学习本教程https://medium.com/@elye.project/android-sqlite-database-unit-testing-is-easy-a09994701162,但是我的测试课程因异常而失败
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类
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资产文件夹中打开的数据库。\?
答案 0 :(得分:0)
乐于to饮整个文件项目很大,因此需要将其放在一个驱动器或Google驱动器上。此应用程序可在FLY上创建SQLite数据库,还可以动态创建表
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);
}
}