Wednesday 31 March 2021

Espresso Mock Web Server not waiting OkHttp Idling Resource with Dagger Hilt

I am trying to write UI test for my Fragments with Espresso and MockWebServer. I am using OkHttp Idling Resource to tell Espresso to wait for the API calls to complete.

But somehow, sometimes my tests are working but sometimes not, because Espresso does its job before service request. So my recyclerView item click test fail.

I can not figure out why espresso does not wait for the API calls? Can anyone help?

Here is my test class

@MediumTest
@HiltAndroidTest
@UninstallModules(PersistenceModule::class, NetworkModule::class)
class MainFragmentTest {

    @get:Rule
    var hiltRule = HiltAndroidRule(this)

    private val mockWebServer = MockWebServer()

    @Inject
    lateinit var okHttp3IdlingResource: OkHttp3IdlingResource

    @Before
    fun setUp() {
        hiltRule.inject()
        // Prepare Mock Web Server
        mockWebServer.start(8080)
        IdlingRegistry.getInstance().register(okHttp3IdlingResource)
    }

    @Test
    fun mainFragmentTest(){

        // Prepare Mock Web Server
        mockWebServer.dispatcher = object : Dispatcher() {
            override fun dispatch(request: RecordedRequest): MockResponse {
                return MockResponse()
                    .setResponseCode(200)
                    .setBody(MockResponseFileReader("post_success.json").content)
            }
        }

        val navController = mockk<NavController>(relaxed = true)

        launchFragmentInHiltContainer<MainFragment> {
            Navigation.setViewNavController(requireView(), navController)
        }

        onView(withId(R.id.rv_posts)).perform(
            RecyclerViewActions.actionOnItemAtPosition<PostViewHolder>(
                0,
                click()
            )
        )


        verify { navController.navigate(MainFragmentDirections.actionMainFragmentToDetailFragment().setPost(any())) }
    }

    @After
    fun tearDown() {
        mockWebServer.close()
    }

}

Here is my TestNetworkModule that holds network dependencies

@Module
@InstallIn(SingletonComponent::class)
object TestNetworkModule {

    /**
     * Provides [OkHttpClient] instance
     */
    @Provides
    @Singleton
    fun provideOkHttpClient() : OkHttpClient {
        return OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .build()
    }

    /**
     * Provides [OkHttp3IdlingResource] instance
     */
    @Provides
    @Singleton
    fun provideIdlingResource(okHttpClient: OkHttpClient) : OkHttp3IdlingResource {
        return OkHttp3IdlingResource.create(
            "okhttp",
            okHttpClient
        )
    }

    /**
     * Provides [Retrofit] instance
     */
    @Provides
    @Singleton
    fun provideRetrofit(okHttpClient: OkHttpClient) : Retrofit {
        val contentType = "application/json".toMediaType()
        return Retrofit.Builder()
            .baseUrl("http://127.0.0.1:8080")
            .client(okHttpClient)
            .addConverterFactory(Json.asConverterFactory(contentType))
            .build()
    }

    /**
     * Provides [ApiService] instance
     */
    @Provides
    @Singleton
    fun provideApiService(retrofit: Retrofit): ApiService {
        return retrofit.create(ApiService::class.java)
    }

}

I do not know what I am missing so any help will be appreciated

Current Versions;

androidTestImplementation "com.squareup.okhttp3:mockwebserver:4.6.0"
androidTestImplementation 'com.jakewharton.espresso:okhttp3-idling-resource:1.0.0'


from Espresso Mock Web Server not waiting OkHttp Idling Resource with Dagger Hilt

No comments:

Post a Comment