Android Комнатный инструментальный тест на сбой при правильном закрытии соединения - PullRequest
0 голосов
/ 05 апреля 2020

Фон

Я запускаю Android инструментальные тесты для тестирования уровня базы данных моего приложения на основе Room. Слой базы данных включает Kotlin сопрограмм и LiveData. С помощью этого ответа StackOverflow я смог получить тесты, работающие с классами Dao, используя @Transaction.

Исправление проблемы с транзакцией (проблема описана в ссылке выше). ) означало добавление этой строки в настройку базы данных в памяти:

db = Room
    .inMemoryDatabaseBuilder(context, AppDatabase::class.java)
    .setTransactionExecutor(Executors.newSingleThreadExecutor()) // <-- this
    .build()

Проблема

С этим добавлением мои тестовые классы базы данных начали падать, когда они содержат несколько тестовых случаев, имеющих дело с с базой данных. Сообщение cra sh:

Test failed to run to completion. Reason: 'Instrumentation run failed due to 'Process crashed.''. Check device logcat for details
Test running failed: Instrumentation run failed due to 'Process crashed.'

Logcat немного более многословно (усечено):

2020-04-05 16:40:05.586 23377-23406/? E/AndroidRuntime: FATAL EXCEPTION: pool-2-thread-1
    Process: org.example.pkg, PID: 23377
    java.lang.RuntimeException: Exception while computing database live data.
        at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:92)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)
     Caused by: java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.
        at android.database.sqlite.SQLiteConnectionPool.throwIfClosedLocked(SQLiteConnectionPool.java:1069)
        at android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:683)

Так что, похоже, Room пытается использовать соединение с базой данных, которое имеет был закрыт уже Я обнаружил, что если я перестану убирать за собой в методе @After в тестовом классе, это будет исправлено:

    @After
    @Throws(IOException::class)
    fun closeDb() {
        // db.close() <-- with this disabled, no errors are thrown
    }

Но это уродливое решение, потому что у меня будут утечки соединений с базой данных. База данных разрушена и установлена ​​между каждым тестом. Я не понимаю, почему тест использует объект подключения другого теста.

Когда происходит этот cra sh, он разрушает всю структуру тестирования - больше не выполняется никаких методов тестирования.

Код

Код класса теста:

@RunWith(AndroidJUnit4::class)
class SomeRepositoryTest {
    private lateinit var db: AppDatabase

    @get:Rule
    val instantTaskExecutorRule = InstantTaskExecutorRule()

    @Before
    fun createDb() {
        val context = ApplicationProvider.getApplicationContext<Context>()
        db = Room
            .inMemoryDatabaseBuilder(context, AppDatabase::class.java)
            .setTransactionExecutor(Executors.newSingleThreadExecutor())
            .build()
    }

    @After
    @Throws(IOException::class)
    fun closeDb() {
        db.close()
    }

    @Test
    fun someTest() {
        runBlocking {
            topicRepository.insert(something)
        }

        val topicAsLiveData = topicRepository.getSomething()
    }
}

Этот класс теста работает правильно, но если я несколько раз скопирую метод someTest(), последующие запуски начнут давать сбой.

Что здесь происходит?

...