简体   繁体   中英

Testing WorkManager with custom initializer and Hilt

I am trying to implement instrumented test for my custom Work Manager which uses Hilt's @AssistedInject.

My Work Manager performs perfect in an app but when I am trying to test it according to Google's work manager integration test guide I'm getting a error:

WM-WorkerFactory: java.lang.NoSuchMethodException: com.android.wmapp.data.SyncWorker. [class android.content.Context, class androidx.work.WorkerParameters]

I've turned off default initialization in AndroidManifest.xml:

    <provider
        android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.androidx-startup"
        tools:node="remove">
    </provider> 

Implemented Configuration.Provider in my Application class:

    @HiltAndroidApp
    class MyApplication : Application(), Configuration.Provider {
        @Inject
        lateinit var workerFactory: HiltWorkerFactory
        override fun getWorkManagerConfiguration(): Configuration {
            return Configuration.Builder().setWorkerFactory(workerFactory)
                .setMinimumLoggingLevel(android.util.Log.DEBUG).build()
        }
    }

Set up my Worker class:

@HiltWorker
class SyncWorker @AssistedInject constructor(
    @Assisted applicationContext: Context,
    @Assisted workerParams: WorkerParameters,
    private val someRepository: SomeRepository,
    private val dispatchers: Dispatchers,
) : CoroutineWorker(applicationContext, workerParams) {
    override suspend fun doWork(): Result {
        val result = withContext(dispatchers.IO) {
            someRepository.synchronize()
        }
        return if (result) Result.success() else Result.retry()
    }
}

My library's test build.gradle configuration:

// Test
testImplementation 'junit:junit:4.+'
androidTestImplementation "androidx.work:work-testing:2.7.1"
androidTestImplementation "com.google.dagger:hilt-android-testing:2.43"
kaptAndroidTest "com.google.dagger:hilt-android-compiler:2.43"
kaptAndroidTest 'com.google.dagger:hilt-compiler:2.43'
kaptAndroidTest 'androidx.hilt:hilt-compiler:1.0.0'
androidTestImplementation "androidx.test:runner:1.4.0"
androidTestImplementation "androidx.test:rules:1.4.0"
androidTestImplementation 'androidx.hilt:hilt-work:1.0.0'
implementation 'androidx.test.ext:junit-ktx:1.1.3'

My instrumented test:

@HiltAndroidTest
class SyncWorkerTest {

    @get:Rule
    val hiltRule = HiltAndroidRule(this)
    private val context: Context = InstrumentationRegistry.getInstrumentation().targetContext

    @Before
    fun setUp() {
        val config = Configuration.Builder()
            .setMinimumLoggingLevel(Log.DEBUG)
            .setExecutor(SynchronousExecutor())
            .build()
        WorkManagerTestInitHelper.initializeTestWorkManager(context, config)
    }

    @Test
    fun testDoWork() {
        val request = SyncWorker.startSyncJob()

        val workManager = WorkManager.getInstance(context)
        val testDriver = WorkManagerTestInitHelper.getTestDriver(context)!!

        workManager.enqueueUniqueWork(
            SyncWorker.SyncWorkName,
            ExistingWorkPolicy.REPLACE,
            request,
        )

        val preRunWorkInfo = workManager.getWorkInfoById(request.id).get()

        Assert.assertEquals(WorkInfo.State.ENQUEUED, preRunWorkInfo.state)

        testDriver.setAllConstraintsMet(request.id)
    }
}

Implemented my own JUnitRunner and specified it in my module's build.gradle:

    class YALTestRunner : AndroidJUnitRunner() {
        override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
            return super.newApplication(cl, HiltTestApplication::class.java.name, context)
        }
    }

testInstrumentationRunner "com.android.wmapp.YALTestRunner"

What have I missed with my WorkManager's test implementation?

I think you have the wrong config in the manifets. Please check here. It should be a bit different for version 2.6 and later:

https://developer.android.com/topic/libraries/architecture/workmanager/advanced/custom-configuration#remove-default

I would say that the issue might be caused by missing HiltWorkerFactory in configuration object provided to initializeTestWorkManager method. Please try to modify your instrumented test:

@HiltAndroidTest
class SyncWorkerTest {

    @Inject
    lateinit var workerFactory: HiltWorkerFactory

    @get:Rule
    val hiltRule = HiltAndroidRule(this)
    private val context: Context = InstrumentationRegistry.getInstrumentation().targetContext

    @Before
    fun setUp() {
        hiltRule.inject()
    
        val config = Configuration.Builder()
            .setMinimumLoggingLevel(Log.DEBUG)
            .setExecutor(SynchronousExecutor())
            .setWorkerFactory(workerFactory)
            .build()
        WorkManagerTestInitHelper.initializeTestWorkManager(context, config)
    }

    @Test
    fun testDoWork() {
        val request = SyncWorker.startSyncJob()

        val workManager = WorkManager.getInstance(context)
        val testDriver = WorkManagerTestInitHelper.getTestDriver(context)!!

        workManager.enqueueUniqueWork(
            SyncWorker.SyncWorkName,
            ExistingWorkPolicy.REPLACE,
            request,
        )

        val preRunWorkInfo = workManager.getWorkInfoById(request.id).get()

        Assert.assertEquals(WorkInfo.State.ENQUEUED, preRunWorkInfo.state)

        testDriver.setAllConstraintsMet(request.id)
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM