question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Issues with classloader when using Roboeletric Extension

See original GitHub issue

I’m trying to migrate this class to kotest using the simplest available technic:

  1. Create new class
  2. extend it from AnnotationSpec
  3. Add RoboelectricExtension to it
  4. Add Roboelectric annotation to this class
  5. Copy-paste code from source class with automatic conversion to kotlin
  6. Fixing some minor syntax issues

Result is as following:

package org.totschnig.myexpenses.util

import io.kotest.core.spec.style.AnnotationSpec
import io.kotest.experimental.robolectric.RobolectricExtension
import io.kotest.experimental.robolectric.RobolectricTest
import junit.framework.Assert
import org.mockito.ArgumentMatchers
import org.mockito.Mockito
import org.totschnig.myexpenses.model.Account
import org.totschnig.myexpenses.model.AccountType.BANK
import org.totschnig.myexpenses.model.AccountType.CASH
import org.totschnig.myexpenses.preference.PrefHandler
import org.totschnig.myexpenses.preference.PrefKey
import org.totschnig.myexpenses.preference.PrefKey.TRANSACTION_WITH_TIME
import org.totschnig.myexpenses.preference.PrefKey.TRANSACTION_WITH_VALUE_DATE
import org.totschnig.myexpenses.util.UiUtils.DateMode

@RobolectricTest
class UiUtilsDateModeKTest : AnnotationSpec() {
    private lateinit var cashAccount: Account
    private lateinit var bankAcount: Account
    private lateinit var prefHandler: PrefHandler

    init {
        extensions(RobolectricExtension())
    }

    @Before
    fun setup() {
        cashAccount = Mockito.mock(Account::class.java)
        bankAcount = Mockito.mock(Account::class.java)
        Mockito.`when`(cashAccount.getType()).thenReturn(CASH)
        Mockito.`when`(bankAcount.getType()).thenReturn(BANK)
        prefHandler = Mockito.mock(PrefHandler::class.java)
    }

    private fun mockPref(prefKey: PrefKey, value: Boolean) {
        Mockito.`when`(prefHandler!!.getBoolean(ArgumentMatchers.eq(prefKey), ArgumentMatchers.anyBoolean())).thenReturn(value)
    }

    @Test
    fun withTimeAndWithValueDate() {
        mockPref(TRANSACTION_WITH_TIME, true)
        mockPref(TRANSACTION_WITH_VALUE_DATE, true)
        Assert.assertEquals(DateMode.DATE_TIME, dateMode(cashAccount))
        Assert.assertEquals(DateMode.BOOKING_VALUE, dateMode(bankAcount))
    }

    @Test
    fun withTimeAndWithoutValueDate() {
        mockPref(TRANSACTION_WITH_TIME, true)
        mockPref(TRANSACTION_WITH_VALUE_DATE, false)
        Assert.assertEquals(DateMode.DATE_TIME, dateMode(cashAccount))
        Assert.assertEquals(DateMode.DATE_TIME, dateMode(bankAcount))
    }


    @Test
    fun withoutTimeAndWithValueDate() {
        mockPref(TRANSACTION_WITH_TIME, false)
        mockPref(TRANSACTION_WITH_VALUE_DATE, true)
        Assert.assertEquals(DateMode.DATE, dateMode(cashAccount))
        Assert.assertEquals(DateMode.BOOKING_VALUE, dateMode(bankAcount))
    }

    @Test
    fun withoutTimeAndWithoutValueDate() {
        mockPref(TRANSACTION_WITH_TIME, false)
        mockPref(TRANSACTION_WITH_VALUE_DATE, false)
        Assert.assertEquals(DateMode.DATE, dateMode(cashAccount))
        Assert.assertEquals(DateMode.DATE, dateMode(bankAcount))
    }

    private fun dateMode(account: Account?): DateMode? {
        return UiUtils.getDateMode(account!!.type, prefHandler)
    }

}

When I’m trying to run this test I’m getting very strange errors like

ClassCastException occurred while creating the mockito mock :
  class to mock : 'org.totschnig.myexpenses.model.Account', loaded by classloader : 'sun.misc.Launcher$AppClassLoader@18b4aac2'
  created class : 'org.totschnig.myexpenses.model.Account$MockitoMock$705451427', loaded by classloader : 'net.bytebuddy.dynamic.loading.MultipleParentClassLoader@762afe37'
  proxy instance class : 'org.totschnig.myexpenses.model.Account$MockitoMock$705451427', loaded by classloader : 'net.bytebuddy.dynamic.loading.MultipleParentClassLoader@762afe37'
  instance creation by : ObjenesisInstantiator

It looks like smth wrong happening in extension, but I don’t know what

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:21 (21 by maintainers)

github_iconTop GitHub Comments

1reaction
asm0deycommented, Apr 21, 2020

Oh, I know!

Code should be like following:

   override suspend fun intercept(testCase: TestCase, execute: suspend (TestCase) -> TestResult): TestResult {

      if (testCase.spec::class.isNotRobolectricClass()) {
         return execute(test)
      }

      val containedRobolectricRunner = ContainedRobolectricRunner()

      beforeTest(containedRobolectricRunner)
      val result = execute(testCase)
      afterTest(containedRobolectricRunner)
      return result
   }
0reactions
asm0deycommented, Apr 25, 2020

Oh, I see, thanks!

Read more comments on GitHub >

github_iconTop Results From Across the Web

robolectric test fails in cli with java.lang.RuntimeException
The key issue is here: Caused by: java.lang.ClassNotFoundException: couldn't load android.content.pm.PackageManager$NameNotFoundException.
Read more >
Oh it seems like the Kotest robolectric extension doesn t in - Kotlinlang
Oh... it seems like the Kotest robolectric extension doesn't initialize the robolectric classloader and environment when the class is created, so all
Read more >
Index - Robolectric
Creates a new builder using the specified ClassLoader for plugin loading. Builder(Config) - Constructor for class org.robolectric.annotation.
Read more >
Help understanding class loading - Google Groups
Robolectric, and when it tries to load my class using that classloader ... fix is to extend RobolectricClassLoader so that tests can add...
Read more >
Developing Android unit and instrumentation tests - Tutorial
Exercise: Write Android instrumentation test and use mocking ... public Application newApplication(ClassLoader cl, String className, Context context) throws ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found