Search code examples
androidkotlinrealmandroid-testing

Realm test fails despite successful saving in Android (Kotlin)


I'm testing a Realm database in an Android app using Kotlin coroutines. I have a ConnectionsRepository with an isEmpty() method, and I'm writing a unit test that asserts behavior before and after saving a Connection object. However, the test fails even though logging indicates successful saving

Methods:

// ConnectionsRepository
override fun isEmpty(): Boolean {
    return RealmManager.getDefaultInstance().use { realm ->
        realm.where(Connection::class.java).count() == 0L
    }
}

suspend fun Connection.save(): Connection? = ConnectionsRepository.saveModel(this) 

override suspend fun saveModel(connection: Connection): Connection? {
    if (connection.createdAt == 0L) connection.createdAt = 
        DateTime.now().withZone(DateTimeZone.UTC).millis
    connection.updatedAt = DateTime.now().withZone(DateTimeZone.UTC).millis

    return withContext(Dispatchers.IO) {
        var savedConnection: Connection? = null
        RealmManager.getDefaultInstance().use { realmDb ->
            realmDb.executeTransaction { transaction ->
                Log.d("RealmTransaction", "Saving connection: $connection")
                savedConnection = realmDb.copyFromRealm(transaction.copyToRealmOrUpdate(connection))
            }
        }
        if (savedConnection == null) {
            Log.e("Error", "Connection was saved with error")
        } else {
            Log.e("Error", "Connection was saved successfully: $savedConnection")
        }
        savedConnection
    }
}

Test:

@RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalCoroutinesApi::class)
class ConnectionsRepositoryTest : DatabaseTestCase() {

    @Test
    @Throws(Exception::class)
    fun isEmptyTest() = runBlockingTest {
        Assert.assertTrue(ConnectionsRepository.isEmpty())

        runBlocking {
            Connection().setGuid("guid1").setId("1").setAccessToken("token4").save()
            advanceUntilIdle()  // Wait for coroutine completion
        }

        Assert.assertFalse(ConnectionsRepository.isEmpty()) 
    } 
} 

Logs:

04-04 16:55:47.713 22806 22836 D RealmTransaction: Saving connection: Connection(...)
04-04 16:55:47.716 22806 22836 E Error: Connection was saved successfully: Connection(...)

Troubleshooting:

I've verified that logging indicates successful saving of the Connection object. I'm using advanceUntilIdle to wait for the coroutine to fully complete.

Question:

Why is my test still failing with an AssertionError? Could this be an issue with Realm caching or synchronization?

Please note:

I'm open to suggestions on improving the test or code structure. If necessary, I can provide additional code snippets, such as RealmManager.getDefaultInstance(). Thank you in advance for any help!


Solution

  • In my case, I was helped by refactoring my current saveModel method, specifically by using executeTransactionAwait. Here’s roughly what it looks like:

    override suspend fun saveModel(connection: Connection): Connection? {
        if (connection.createdAt == 0L) connection.createdAt = DateTime.now().withZone(DateTimeZone.UTC).millis
        connection.updatedAt = DateTime.now().withZone(DateTimeZone.UTC).millis
    
        var resultConnection: Connection? = null
        RealmManager.getDefaultInstance().use { realmDb ->
            realmDb.executeTransactionAwait { transactionRealm ->
                resultConnection = transactionRealm.copyFromRealm(transactionRealm.copyToRealmOrUpdate(connection))
            }
        }
        return resultConnection
    }