Hilt Instrumentation test with Workmanager not working
Asked Answered
B

2

6

When I try to run an ActivityScenario in my application that contains a WorkManager I get the following error on start:

java.lang.IllegalStateException: WorkManager is not initialized properly.  You have explicitly disabled WorkManagerInitializer in your manifest, have not manually called WorkManager#initialize at this point, and your Application does not implement Configuration.Provider.

Using the WorkManagerTestInitHelper from the work-test artifact doesnt help either.

The WorkManager is defined like this:

@Provides
@Singleton
fun provideWorkmanager(@ApplicationContext context: Context) = WorkManager.getInstance(context)

This is my test atm:

    @HiltAndroidTest
    @RunWith(AndroidJUnit4::class)
    class LoginTest {
    
        @get:Rule(order = 0)
        var hiltRule = HiltAndroidRule(this)
    
        @get:Rule(order = 1)
        val activityRule = ActivityScenarioRule(MainActivity::class.java)
    
        @Before
        fun before() {
            val context = InstrumentationRegistry.getInstrumentation().targetContext
            val config = Configuration.Builder()
                .setMinimumLoggingLevel(Log.DEBUG)
                .setExecutor(SynchronousExecutor())
                .build()
            WorkManagerTestInitHelper.initializeTestWorkManager(context, config)
        }
    
        @Test
        fun test() {
            ...
        }

}
Babs answered 31/8, 2020 at 13:0 Comment(0)
D
3

This is because @get:Rule executes before the @Before does, as per the Google Documentation:

This rule provides functional testing of a single activity. The activity under test is launched before each test annotated with @Test and before any method annotated with @Before. It's terminated after the test is completed and all methods annotated with @After are finished. To access the activity under test in your test logic, provide a callback runnable to ActivityScenarioRule.getScenario().onActivity().

In order to fix this, you would need to initialise the WorkManager in the test with WorkManagerTestInitHelper before you try to launch the activity.

To do this, you should avoid using ActivityScenarioRule and use ActivityScenario instead, you can do something like this:

@HiltAndroidTest
@RunWith(AndroidJUnit4::class)
class LoginTest {
    private lateinit var scenario: ActivityScenario<MainActivity>

    @get:Rule
    var hiltRule = HiltAndroidRule(this)

    @Before
    fun before() {
        val context = InstrumentationRegistry.getInstrumentation().targetContext
        val config = Configuration.Builder()
            .setMinimumLoggingLevel(Log.DEBUG)
            .setExecutor(SynchronousExecutor())
            .build()
        WorkManagerTestInitHelper.initializeTestWorkManager(context, config)

        scenario = launchActivity()
    }

    @Test
    fun test() {
        scenario.moveToState(Lifecycle.State.CREATED).onActivity { 
             activity -> // do some test with the activity
        }
    }
}
Duologue answered 3/11, 2020 at 11:38 Comment(1)
Oh wow I had similar problems trying to instrument with Hilt - the app would start running on its own merry way before my @Before was even finished - this appears to have solved my issue. Thank you! launchActivity() should be ActivityScenario.launch(MainActivity::class.java) (or whatever activity you want to launchDrawshave
G
3

To take advantage of ActivitScenarioRule and ensure that the WorkManager is initialized first I created a custom JUnit rule.

class WorkManagerRule : TestRule {
override fun apply(base: Statement?, description: Description?): Statement {
    return object : Statement() {
        override fun evaluate() {
            val context = InstrumentationRegistry.getInstrumentation().targetContext
            val config = Configuration.Builder()
                .setMinimumLoggingLevel(Log.DEBUG)
                .setExecutor(SynchronousExecutor())
                .build()
            WorkManagerTestInitHelper.initializeTestWorkManager(context, config)
            try {
                base?.evaluate()
            } finally {
                Log.d("WorkManagerRule", "Do some teardown")
            }
        }

    }
}


@RunWith(AndroidJUnit4::class)
@HiltAndroidTest
class MyTest {
    @get:Rule(order = 0)
    var hiltRule = HiltAndroidRule(this)

    @get:Rule(order = 1)
    var workMgrRule = WorkManagerRule()

    @get:Rule(order = 2)
    var activityRule = ActivityScenarioRule(MainActivity::class.java)

    @Before
    fun init() {
        hiltRule.inject()
    }

    //Your test code here...
}

I used the instructions for creating JUnit rules found here.

Gentlemanatarms answered 28/5, 2021 at 23:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.