'Accessing Common Coroutine Rule From All Modules - Android Unit Test

I have a TestWatcher class implementing TestCoroutineScope interface as follows:

@ExperimentalCoroutinesApi
class MainCoroutineRule(private val dispatcher: TestCoroutineDispatcher = TestCoroutineDispatcher()) :
TestWatcher(),
TestCoroutineScope by TestCoroutineScope(dispatcher) {
    override fun starting(description: Description?) {
        super.starting(description)
        Dispatchers.setMain(dispatcher)
    }

    override fun finished(description: Description?) {
        super.finished(description)
        cleanupTestCoroutines()
        Dispatchers.resetMain()
    }
}

This is used to provide Loopers to ViewModelTests using kotlin coroutines, for example:

@RunWith(JUnit4::class)
class BlaViewModelTest {

    @get:Rule
    val instantExecutorRule = InstantTaskExecutorRule()

    @ExperimentalCoroutinesApi
    @get:Rule
    val coroutineRule = MainCoroutineRule()

    @MockK
    lateinit var blaUseCase: BlaUseCase

    private lateinit var blaViewModel: BlaViewModel

    @Before
    fun setup() {
        MockKAnnotations.init(this)
        blaViewModel = BlaViewModel(blaUseCase)
    }

    @Test
    fun testBla_Positive() {
        coEvery {
            blaUseCase.execute(any()).await()
        } returns Resource.Success(Bla("data"))

        blaViewModel.blaLiveData.observeForever {}
        blaViewModel.bla()

        assert(blaViewModel.blaLiveData.value != null)
        assert(blaViewModel.blaLiveData.value is Resource.Success)
        assert((blaViewModel.blaLiveData.value as? Resource.Success)?.value?.data == "data")
    }
}

My problem is that I can only access MainCoroutineRule from the same module test directory where BlaViewModelTest remains.

If I move MainCoroutineRule to a test directory in a common module, let's say base, BlaViewModelTest cannot access MainCoroutineRule during test run time failing at the end. There is no problem in compile time.

I tried to move MainCoroutineRule into main package of base, but it forced me to implement test libraries in project which is not a good approach from my point of view.

I don't want to duplicate MainCoroutineRule for all modules, I want to access it from a common source.

Any approaches will be appreciated.



Solution 1:[1]

If I move MainCoroutineRule to a test directory in a common module, let's say base, BlaViewModelTest cannot access MainCoroutineRule during test run time failing at the end. There is no problem in compile time.

Test sources won't be available in consumer modules. I'm don't know why they're available at compile-time and why the IDE doesn't complain about it, but I definitely experienced the same thing.

To solve this you can create a separate test-only module (e.g. base-testing, test-utils). The rule should be part of the module's normal sources (src/main, not src/test). Then you can include that module as testImplementation in your consumer modules.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Alex Krupa