java - Android 的 SQLiteOpenHelper 测试类

标签 java android junit mockito

我正在尝试为 Android 开发人员中的 SQLite 数据库的访问器类编写单元测试。但是,当我运行测试类时,出现以下错误:

java.lang.RuntimeException: Method getWritableDatabase in android.database.sqlite.SQLiteOpenHelper not mocked. See http://g.co/androidstudio/not-mocked for details.

at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java)
at com.example.jack.app4.helper.CharityHelper.insertData(CharityHelper.java:54)
at helper.TestCharityHelper.testInsertAndSelectAll(TestCharityHelper.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
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.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
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.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

问题是我在测试的 onSetup 中创建的 CharityHelper 实例为空,但我不知道如何解决这个问题。任何帮助将不胜感激。

要测试的我的访问器类:

/**
 * Accessor class for Charity Table.
 *
 * Created by Jack on 07/09/2017.
 */

public class CharityHelper extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "Example.db";
    private static final String TABLE_NAME = "Charity";
    private static final String ID = "id";
    private static final String CHARITY_NAME = "charityName";
    private static final String CHARITY_NUMBER = "charityNumber";
    private static final String POSTCODE= "postCode";
    private static final String CHARITY_TYPE= "charityType";


    public CharityHelper(Context context) {
        super(context, DATABASE_NAME, null , 1);
//        SQLiteDatabase db = this.getWritableDatabase();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + TABLE_NAME + " (ID INTEGER PRIMARY KEY AUTOINCREMENT, CHARITY_NAME TEXT, CHARITY_NUMBER INTEGER, POSTCODE VARCHAR, GENRE VARCHAR)");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int i, int i1) {
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
        onCreate(db);
    }


    /**
     * Insert record into charity table.
     * @param charity - charity to be inserted
     * @return boolean - whether insert was successful or not.
     */
    public boolean insertData(Charity charity) {
        SQLiteDatabase db = this.getWritableDatabase();

        ContentValues contentValues = new ContentValues();
        contentValues.put(CHARITY_NAME, charity.getName());
        contentValues.put(CHARITY_NUMBER, charity.getNumber());
        contentValues.put(POSTCODE, charity.getPostcode());
        contentValues.put(CHARITY_TYPE, charity.getCharityType().toString());

        long result = db.insert(TABLE_NAME, null, contentValues);

        return result != -1;
    }


    /**
     * Method to return list of all charities in db.
     * Will return empty list if no record found.
     * @return List<Charity>
     */
    public List<Charity> selectAll() {
        SQLiteDatabase db = this.getReadableDatabase();

        Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_NAME, null);

        return getCharitiesListFromCursor(cursor);
    }


    /**
     * Method to return list of all charities in db of the charity type passed in.
     * Will return empty list if no record found.
     * @return List<Charity>
     */
    public List<Charity> selectByCharityType(Charity.CharityType charityType) {
        SQLiteDatabase db = this.getReadableDatabase();

        Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_NAME + " WHERE genre = ?", new String[] {charityType.toString()});

        return getCharitiesListFromCursor(cursor);
    }

    /**
     * Takes cursor from db query and convert into list of charities.
     * @param cursor - passed in cursor
     * @return List Charity
     */
    private List<Charity> getCharitiesListFromCursor(Cursor cursor) {
        List<Charity> charityList = new ArrayList<>();

        while (cursor.moveToNext()) {
            charityList.add(new Charity(
                    cursor.getString(cursor.getColumnIndex(CHARITY_NAME)),
                    cursor.getLong(cursor.getColumnIndex(CHARITY_NUMBER)),
                    cursor.getString(cursor.getColumnIndex(POSTCODE)),
                    Charity.CharityType.valueOf(cursor.getString(cursor.getColumnIndex(CHARITY_TYPE)))
            ));
        }
        return charityList;
    }

}

我的测试类:

 /**
 * Test class for Charity Helper
 * Created by Jack on 10/09/2017.
 */

@RunWith(MockitoJUnitRunner.class)
public class TestCharityHelper {

    private Charity testCharity;
    private CharityHelper charityHelper;

    private final String testCharityName = "testName";
    private final Long testCharityNumber = 1234L;
    private final String testCharityPostcode = "CO10 8NP";
    private final Charity.CharityType testCharityType = Charity.CharityType.ANIMAL;

    @Mock
    SQLiteDatabase dbMock;

    @Mock Context mockContext;

    @Before
    public void onSetup() {

        charityHelper = new CharityHelper(mockContext);
        testCharity = new Charity(testCharityName,testCharityNumber,testCharityPostcode,testCharityType);
    }

    @After
    public void tearDown() throws Exception{
        charityHelper.close();
//        super.tearDown();
    }


    @Test
    public void testInsertAndSelectAll() {
        charityHelper.insertData(testCharity);

        List<Charity> returnedCharityList = charityHelper.selectAll();

        assertTrue(returnedCharityList.contains(testCharity));

    }
}

最佳答案

在您的设置方法中,您需要使用 RenamingDelegatingContext() 方法返回的上下文。您还需要扩展 AndroidTestCase 类

public class TestCharityHelper extends AndroidTestCase{

 .
 .
 private RenamingDelegatingContext mockContext;


 public void setUp() throws Exception {
    super.setUp();


    final String prefix = "test";
    mockContext = new RenamingDelegatingContext(getContext(),prefix);

    charityHelper = new CharityHelper(mockContext);
    testCharity = new Charity(testCharityName,testCharityNumber,testCharityPostcode,testCharityType);
}

关于java - Android 的 SQLiteOpenHelper 测试类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46169722/

相关文章:

android - 带防伪、token、cookie 和参数的 Http post

java - Mockito 说 "Wanted but not invoked"但调试测试跳转到那个方法

unit-testing - 在其自己的 JVM 中与每个测试类并行收集并运行所有 junit 测试(按类并行化,而不是按方法并行化)

junit - 如何使用 PowerMockito 捕获构造函数参数

java - Android:Firebase 需要太多时间来获取数据

java - 在UDP Socket java android上发送和接收数据

java - 从 vlcj 播放器数组中播放视频

java - 带 vector 的自由飞行相机 - 如何正确旋转?

java - 在 Java 中为 JOGL 释放直接缓冲区 native 内存

java - 如何上传其中包含图像文件的表单,AngularJS spring