即使使用Mockito在Android中通过单元测试,也始终会出现线程错误

use*_*656 5 android mocking mockito powermockito

即使测试通过而且不确定原因,我总是会收到错误.这次我检查如果视图为空则有一个空指针.

@Before
public void setUp() {
   MockitoAnnotations.initMocks(this);
   mockView = mock(CollectionContract.View.class);
   // Get a reference to the class under test
   presenter = new CollectionPresenter(repository, mockView);
}


@Test(expected = NullPointerException.class)
  public void testShowingUIWhenViewIsNull() {
      presenter = new CollectionPresenter(repository, null);
      verify(mockView).showAddCollection();
 }
Run Code Online (Sandbox Code Playgroud)

这是堆栈跟踪:

Exception in thread "Thread-2" android.database.sqlite.SQLiteException: Cannot prepare statement, base error code: -92
    at org.robolectric.shadows.ShadowSQLiteConnection$Connections.getSqliteException(ShadowSQLiteConnection.java:632)
    at org.robolectric.shadows.ShadowSQLiteConnection$Connections.execute(ShadowSQLiteConnection.java:601)
    at org.robolectric.shadows.ShadowSQLiteConnection$Connections.prepareStatement(ShadowSQLiteConnection.java:525)
    at org.robolectric.shadows.ShadowSQLiteConnection.nativePrepareStatement(ShadowSQLiteConnection.java:93)
    at android.database.sqlite.SQLiteConnection.nativePrepareStatement(SQLiteConnection.java)
    at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:889)
    at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:500)
    at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
    at android.database.sqlite.SQLiteProgram.__constructor__(SQLiteProgram.java:58)
    at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java)
    at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java)
    at android.database.sqlite.SQLiteDatabase.compileStatement(SQLiteDatabase.java:994)
    at android.database.DatabaseUtils.longForQuery(DatabaseUtils.java:811)
    at android.database.sqlite.SQLiteDatabase.getVersion(SQLiteDatabase.java:864)
    at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:241)
    at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
    at co.uk.rushorm.android.AndroidRushStatementRunner.runRaw(AndroidRushStatementRunner.java:37)
    at co.uk.rushorm.core.RushCore$12.statementCreated(RushCore.java:473)
    at co.uk.rushorm.core.implementation.ReflectionTableStatementGenerator.generateStatements(ReflectionTableStatementGenerator.java:46)
    at co.uk.rushorm.core.RushCore.createTables(RushCore.java:469)
    at co.uk.rushorm.core.RushCore.access$200(RushCore.java:39)
    at co.uk.rushorm.core.RushCore$1.run(RushCore.java:130)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.util.concurrent.ExecutionException: com.almworks.sqlite4java.SQLiteException: [-92] DB[1] is not confined or already disposed
    at java.util.concurrent.FutureTask.report(FutureTask.java:122)
    at java.util.concurrent.FutureTask.get(FutureTask.java:192)
    at com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly(Uninterruptibles.java:142)
    at org.robolectric.shadows.ShadowSQLiteConnection$Connections.execute(ShadowSQLiteConnection.java:596)
    at org.robolectric.shadows.ShadowSQLiteConnection$Connections.prepareStatement(ShadowSQLiteConnection.java:525)
    at org.robolectric.shadows.ShadowSQLiteConnection.nativePrepareStatement(ShadowSQLiteConnection.java:93)
    at sun.reflect.GeneratedMethodAccessor3.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.robolectric.internal.bytecode.ShadowWrangler$ShadowMethodPlan.run(ShadowWrangler.java:548)
    at android.database.sqlite.SQLiteConnection.nativePrepareStatement(SQLiteConnection.java)
    at android.database.sqlite.SQLiteConnection.$$robo$$acquirePreparedStatement(SQLiteConnection.java:889)
    at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java)
    at android.database.sqlite.SQLiteConnection.$$robo$$prepare(SQLiteConnection.java:500)
    at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java)
    at android.database.sqlite.SQLiteSession.$$robo$$prepare(SQLiteSession.java:588)
    at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java)
    at android.database.sqlite.SQLiteProgram.$$robo$$__constructor__(SQLiteProgram.java:58)
    at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java)
    at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java)
    at android.database.sqlite.SQLiteDatabase.$$robo$$compileStatement(SQLiteDatabase.java:994)
    at android.database.sqlite.SQLiteDatabase.compileStatement(SQLiteDatabase.java)
    at android.database.DatabaseUtils.$$robo$$longForQuery(DatabaseUtils.java:811)
    at android.database.DatabaseUtils.longForQuery(DatabaseUtils.java)
    at android.database.sqlite.SQLiteDatabase.$$robo$$getVersion(SQLiteDatabase.java:864)
    at android.database.sqlite.SQLiteDatabase.getVersion(SQLiteDatabase.java)
    at android.database.sqlite.SQLiteOpenHelper.$$robo$$getDatabaseLocked(SQLiteOpenHelper.java:241)
    at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java)
    at android.database.sqlite.SQLiteOpenHelper.$$robo$$getWritableDatabase(SQLiteOpenHelper.java:163)
    at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java)
    ... 7 more
Caused by: com.almworks.sqlite4java.SQLiteException: [-92] DB[1] is not confined or already disposed
    at com.almworks.sqlite4java.SQLiteConnection.checkThread(SQLiteConnection.java:1386)
    at com.almworks.sqlite4java.SQLiteConnection.prepare(SQLiteConnection.java:451)
    at com.almworks.sqlite4java.SQLiteConnection.prepare(SQLiteConnection.java:542)
    at com.almworks.sqlite4java.SQLiteConnection.prepare(SQLiteConnection.java:529)
    at org.robolectric.shadows.ShadowSQLiteConnection$Connections$2.call(ShadowSQLiteConnection.java:529)
    at org.robolectric.shadows.ShadowSQLiteConnection$Connections$2.call(ShadowSQLiteConnection.java:525)
    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)
    ... 1 more
Run Code Online (Sandbox Code Playgroud)

如果视图存在,为什么sql异常会出现在show view ui上?坚持这一点,因为我几乎在每次测试中都能找到它.任何想法都会很棒.谢谢.

azi*_*ian 1

从这一行来看:

Caused by: com.almworks.sqlite4java.SQLiteException: [-92] DB[1] is not confined or already disposed
Run Code Online (Sandbox Code Playgroud)

并通过前一行

at com.almworks.sqlite4java.SQLiteConnection.checkThread(SQLiteConnection.java:1386)
Run Code Online (Sandbox Code Playgroud)

人们可能会得出结论,checkThread它的作用是检查查询是否在最初创建数据库的线程上执行,并且该检查未通过。

确保您在同一线程上创建和查询数据库。基本上,您必须为数据库操作指定一个单独的线程。

这是来源checkThread()的方法:

void checkThread() throws SQLiteException {
    Thread confinement = myConfinement;
    if (confinement == null) {
      throw new SQLiteException(WRAPPER_MISUSE, this + " is not confined or already disposed");
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

并且在方法中myConfinementnull-ed dispose()。因此,还要确保您没有dispose()退出连接。