In my instrumentation tests I have noticed that my Retrofit components are created before the test even does the hiltRule.inject()
command.
This is probably because I'm using WorkManager and early entry point components
open class BaseApplication : Application(), Configuration.Provider {
override fun getWorkManagerConfiguration(): Configuration {
return Configuration.Builder().setWorkerFactory(
EarlyEntryPoints.get(
applicationContext,
WorkerFactoryEntryPoint::class.java
).workerFactory
).build()
}
@EarlyEntryPoint
@InstallIn(SingletonComponent::class)
interface WorkerFactoryEntryPoint {
val workerFactory: HiltWorkerFactory
}
}
@CustomTestApplication(BaseApplication::class)
interface HiltTestApplication
I want to inject an OkHttp3 MockWebServer in my tests and also in the Retrofit interceptors so that I can determine which port is being used (from mockWebServer.start()
) and set up my mocks accordingly but, despite marking my MockWebServer wrapper class as a Singleton I can see multiple instances of it being created, which therefore have different port numbers.
It looks like it creates one instance of MockWebServer when the application is created and then another when the test is injected but presumably this means that my mocks aren't correctly defined.
@Singleton
class MockWebServerWrapper @Inject constructor() {
private val mockWebServer by lazy { MockWebServer() }
val port get() = mockWebServer.port
fun mockRequests() {
...
}
}
Is there a more correct way to share the same mock webserver between my Retrofit Interceptors defined for the WorkManager and those needed for network requests within the test activity itself?
After the comments from Levon below, I made the changes to BaseApplication, created the ApplicationInjectionExecutionRule and updated the BaseTest class so that the rules read like this:
@get:Rule(order = 0)
val disableAnimationsRule = DisableAnimationsRule()
private lateinit var hiltRule: HiltAndroidRule
@get:Rule(order = 1)
val ruleChain: RuleChain by lazy {
RuleChain
.outerRule(HiltAndroidRule(this).also { hiltRule = it })
.around(ApplicationInjectionExecutionRule())
}
@get:Rule(order = 2)
val composeTestRule = createAndroidComposeRule<MainActivity>()
But I was still seeing the errors for the (Urban) Airship takeoff which is why I'd move the WorkManagerConfiguration to EarlyEntryPoints to begin with.
E Scheduler failed to schedule jobInfo com.urbanairship.job.SchedulerException: Failed to schedule job at com.urbanairship.job.WorkManagerScheduler.schedule(WorkManagerScheduler.java:31)
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property workerFactory has not been initialized at com.gocitypass.BaseApplication.getWorkManagerConfiguration(BaseApplication.kt:33)