0

In my Android Kotlin project, I have a class, with a function running a coroutine, that I want to test using an instrumented test (not unit test).

Here is what it looks like:

class DemoClass
{
    fun demo(liveData: MutableLiveData<String>)
    {
        CoroutineScope(IO).launch {
            val result = doStuff()
            withContext(Main) { liveData.value = result }
        }
    }
}

In my instrumented test class, here is what I tried:

@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest
{
    @ExperimentalCoroutinesApi
    @Test
    fun testCoroutine() = runBlockingTest {
        val demoClass = DemoClass()
        val liveData = MutableLiveData<String>()
        demoClass.demo(liveData)
        assertEquals("demo", liveData.value)
    }
}

Unfortunately, it's not working. It seems like runBlockingTest {} is only available for unit testing, not instrumented testing. Here is my error when I run the test:

java.lang.NoClassDefFoundError: Failed resolution of: Lkotlinx/coroutines/test/TestBuildersKt;

So how can I test DemoClass.demo() and the liveData value in an instrumented test?

Thanks.

EDIT

I also tried this:

@ExperimentalCoroutinesApi
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest
{
    private val testDispatcher = TestCoroutineDispatcher()

    @Before
    fun setup() {
        Dispatchers.setMain(testDispatcher)
    }

    @After
    fun tearDown() {
        Dispatchers.resetMain()
        testDispatcher.cleanupTestCoroutines()
    }

    @Test
    fun testCoroutine(): Unit = runBlocking {
        val demoClass = DemoClass()
        val liveData = MutableLiveData<String>()
        demoClass.demo(liveData)
        assertEquals("demo", liveData.value)
    }
}

The test runs, but I got this:

java.lang.AssertionError: 
Expected :demo
Actual   :null
matteoh
  • 2,810
  • 2
  • 29
  • 54

1 Answers1

0

I've been using just runBlocking {} instead of runBlockingTest to success.

I know technically runBlockingTest is the right way I believe the major difference is how delays are handled.

Possibly try these flags in your test class to bypass that difference,

    @JvmField
    val instantExecutorRule = InstantTaskExecutorRule()

    @ExperimentalCoroutinesApi
    @get:Rule
    var mainCoroutineRule = MainCoroutineRule()
Mike dg
  • 4,648
  • 2
  • 27
  • 26
  • Still not working for me. Could you provide a small example, by any chance? – matteoh Jun 13 '20 at 11:14
  • hmm, have you verified that you have androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.7' in your build.gradle? also added some more details – Mike dg Jun 13 '20 at 11:22
  • Thanks, and yes, I have that implementation, but I still don't manage to make it work (it's testImplementation, btw). I edited my post, for your information. – matteoh Jun 13 '20 at 11:56
  • 1
    if you want the library to be available to the instrumented tests and not unit tests you should use androidTestImplementation as Mike suggested – Gustavo Pagani Jun 13 '20 at 17:20