Test a Worker with Hilt Dependency Injection

90 Views Asked by At

I'm trying to test my worker class, but when I attempt to create the worker instance, it gives me this error

java.lang.IllegalStateException: Could not create an instance of ListenableWorker

This is the code of my Worker class

@HiltWorker
class MyWorker @AssistedInject constructor(
    @Assisted private val context: Context,
    @Assisted parameters: WorkerParameters,
    private val repository: IMyRepository // this is an interface 
) : CoroutineWorker(context, parameters) {
    ////
}

I'm trying to test my worker with this code:

@HiltAndroidTest
class WorkerTest {

    @get:Rule
    val hiltRule = HiltAndroidRule(this)
    private lateinit var appContext: Context

    @Before
    fun setUp() {
        appContext = ApplicationProvider.getApplicationContext()
        hiltRule.inject()
    }

    @Test
    fun testMyWorker() {
        val worker = TestListenableWorkerBuilder<DecryptionWorker>(
            context = appContext,
        ).build() // Error on this line
    }
}

And this code is my test repository implementation:

@Singleton
class TestMyRepositoryImpl @Inject constructor(): IMyRepository {
    ////
}

I'm not sure, but I think this is the correct way to bind my test repository and replace my actual CoreModule

@Module
@TestInstallIn(
    components = [SingletonComponent::class],
    replaces = [CoreModule::class]
)
abstract class TestCoreModule {
    @Binds
    abstract fun provideMyRepository(myRepositoryImpl: TestMyRepositoryImpl): IMyRepository
}
1

There are 1 best solutions below

0
segoSambel On BEST ANSWER

I learned from this article that you can create a worker factory and use it to create an instance of your worker. With that said, here's my current implementation.

class TestWorkerFactory(
    private val myRepository: IMyRepository
) : WorkerFactory() {
    override fun createWorker(
        appContext: Context,
        workerClassName: String,
        workerParameters: WorkerParameters
    ): ListenableWorker? {
        return when (workerClassName) {
            MyWorker::class.java.name -> MyWorker(
                appContext,
                workerParameters,
                myRepository
            )

            else -> null
        }
    }
}

Since I'm still using the TestCoreModule, this is my current test code:

@HiltAndroidTest
class WorkerTest {

    @get:Rule
    val hiltRule = HiltAndroidRule(this)

    private lateinit var appContext: Context

    @Inject
    lateinit var myRepository: IMyRepository

    @Before
    fun setUp() {
        appContext = ApplicationProvider.getApplicationContext()
        hiltRule.inject()
    }

    @Test
    fun testMyWorker() {
        val worker = TestListenableWorkerBuilder<MyWorker>(
            context = appContext
        ).setWorkerFactory(
            TestWorkerFactory(myRepository)
        ).build()

        // The rest of my test code
    }
}

Note: I'm open to feedback and learning from others, so if you happen to notice any flaws in my current implementation, please feel free to share your insights. I'm continuously learning.