Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(DAGGER-ANDROID) Can not use @Inject on an Espresso Test and can not use mockWebServer

I'm trying to create Espresso tests and using a mockWebServer the thing is when I try to create my mockWebServer it calls the real api call and I want to intercept it and mock the response.

My dagger organisation is :

My App

open class App : Application(), HasAndroidInjector {

    lateinit var application: Application

    @Inject
    lateinit var androidInjector: DispatchingAndroidInjector<Any>

    override fun androidInjector(): AndroidInjector<Any> = androidInjector

    override fun onCreate() {
        super.onCreate()
        DaggerAppComponent.factory()
            .create(this)
            .inject(this)
        this.application = this
    }
}

Then MyAppComponent

@Singleton
@Component(
    modules = [
        AndroidInjectionModule::class,
        AppModule::class,
        RetrofitModule::class,
        RoomModule::class,
        AppFeaturesModule::class
    ]
)
interface AppComponent : AndroidInjector<App> {

    @Component.Factory
    interface Factory {
        fun create(@BindsInstance application: App): AppComponent
    }
}

Then I've created this TestApp

class TestApp : App() {

    override fun androidInjector(): AndroidInjector<Any> = androidInjector

    override fun onCreate() {
        DaggerTestAppComponent.factory()
            .create(this)
            .inject(this)
    }
}

And this is my TestAppComponent

@Singleton
@Component(
    modules = [
        AndroidInjectionModule::class,
        AppModule::class,
        TestRetrofitModule::class,
        AppFeaturesModule::class,
        RoomModule::class]
)
interface TestAppComponent : AppComponent {
    @Component.Factory
    interface Factory {
        fun create(@BindsInstance application: App): TestAppComponent
    }
}

Note: Here I've created a new module, called TestRetrofitModule where the BASE_URL is "http://localhost:8080", I don't know if I need something else.

Also I've created the TestRunner

class TestRunner : AndroidJUnitRunner() {

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

}

And put it on the testInstrumentationRunner

Problem 1

I can not use

@Inject
lateinit var okHttpClient: OkHttpClient

because it says that it's not initialised.

Problem 2 (Solved thanks Skizo)

My mockWebServer is not dispatching the responses even-though is not pointing the real api call, is pointing the one that I've put to the TestRetrofitModule, the thing is that I have to link that mockWebServer and Retrofit.

like image 998
StuartDTO Avatar asked May 01 '20 08:05

StuartDTO


2 Answers

The setup you posted looks correct. As for App not being provided, you probably need to bind it in your component, since right now you're binding TestApp only. So you need to replace

fun create(@BindsInstance application: TestApp): TestAppComponent

with

fun create(@BindsInstance application: App): TestAppComponent
like image 189
wasyl Avatar answered Sep 21 '22 11:09

wasyl


I had the same problem with mockWebServer recently, what you need to do is to put a breakpoint and see what's the error, in my case I put it on my BaseRepository where I was doing the call, and found that the exception was :

java.net.UnknownServiceException: CLEARTEXT communication to localhost not permitted by network security policy

What I did to solve the problem is add this on my manifest.xml

android:usesCleartextTraffic="true"

But you may have to use other approaches you can take a look on android-8-cleartext-http-traffic-not-permitted.

like image 39
Skizo-ozᴉʞS Avatar answered Sep 25 '22 11:09

Skizo-ozᴉʞS