Search code examples
androidkotlinandroid-workmanagerdagger-hilt

Android instrumentation test using Hilt and Work Manager results in java.lang.NoSuchMethodException


I would like to write an instrumentation test to test a custom worker. My application uses Hilt for dependency injection. My custom worker requires assisted injection as it has an additional parameter in the constructor. When running the instrumentation test the customer worker does not get instantiated as a result of an exception.

Details

The Error

E/WM-WorkerFactory: Could not instantiate com.poliziano.notanotherpomodoroapp.core.storage.PreferenceSyncWorker
    java.lang.NoSuchMethodException: <init> [class android.content.Context, class androidx.work.WorkerParameters]

See the full error logs here.

The Worker

@HiltWorker
class PreferenceSyncWorker @AssistedInject constructor(
    @Assisted context: Context,
    @Assisted appParameters: WorkerParameters,
    // additional dependency to be injected
    private val restApi: RestApi
) : Worker(context, appParameters) {
    override fun doWork(): Result {
        return Result.success()
    }
}

The Test

// A custom runner to set up the instrumented application class for tests.
class CustomTestRunner : AndroidJUnitRunner() {
    override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
        return super.newApplication(cl, HiltTestApplication::class.java.name, context)
    }
}

@HiltAndroidTest
@RunWith(AndroidJUnit4::class)
class BasicInstrumentationTest {

    @get:Rule(order = 0)
    val hiltRule = HiltAndroidRule(this)

    @Before
    fun setup() {
        val context = ApplicationProvider.getApplicationContext<Context>()
        val config = Configuration.Builder()
            .setMinimumLoggingLevel(Log.DEBUG)
            .setExecutor(SynchronousExecutor())
            .build()

        // Initialize WorkManager for instrumentation tests.
        WorkManagerTestInitHelper.initializeTestWorkManager(context, config)
    }

    @Test
    fun shouldSyncPreference() {
        // Create request
        val request = OneTimeWorkRequestBuilder<PreferenceSyncWorker>()
            .build()

        val workManager = WorkManager.getInstance(ApplicationProvider.getApplicationContext())
        // Enqueue and wait for result. This also runs the Worker synchronously
        // because we are using a SynchronousExecutor.
        workManager.enqueue(request).result.get()
        // Get WorkInfo and outputData
        val workInfo = workManager.getWorkInfoById(request.id).get()

        // Assert
        assertThat(workInfo.state).isEqualTo(WorkInfo.State.SUCCEEDED)
    }
}


Solution

  • A common issue is the WorkManager not being disabled in the AndroidManifest. In my case, it was a missing dependency: kapt "androidx.hilt:hilt-compiler:1.0.0".

    There are two Hilt compiler dependencies:

    • kapt "com.google.dagger:hilt-compiler:2.5.0" which is for the core Hilt library.
    • kapt "androidx.hilt:hilt-compiler:1.0.0" which is required for Jetpack architecture libraries - such as WorkManager.