How to make MockWebServer work?

Leandro Borges Ferreira picture Leandro Borges Ferreira · Dec 28, 2016 · Viewed 7.1k times · Source

I am developing an app using the MVP architecture. I am trying to test the Interactors of my app using MockWebServer. Well, I have this test:

@RunWith(RobolectricTestRunner::class)
@Config(constants = BuildConfig::class, manifest = "src/main/AndroidManifest.xml", packageName = "br.com.simplepass.simplepassnew", sdk = intArrayOf(23))
class LoginInteractorImplTest {

    lateinit var mLoginInteractor : LoginInteractor
    lateinit var mServer: MockWebServer


    @Before
    fun setUp(){
        mLoginInteractor = LoginInteractorImpl()
        mServer = MockWebServer()
        mServer.start()
    }

    @Test
    fun loginTest(){
        mServer.url("http://192.168.0.10:8080/login")

        val testSubscriber = TestSubscriber.create<User>()

        mLoginInteractor.login("31991889992", "lala").subscribe(testSubscriber)
        testSubscriber.assertNoErrors()
//        testSubscriber.assertCompleted()
    }

    @After
    fun tearDown(){
        mServer.shutdown()
    }
}

But, when I uncomment the assertCompleted on the TestSubscriber, I always get assertionError... I know the TestSubscriber works, because I use it in other tests.

Here is my ApiCall:

@GET("login")
fun login() : Observable<User>

My NetModule:

@Module
class NetModule(val mBaseUrl: String) {

    @Provides
    @Singleton
    fun provideHttpCache(application: Application): Cache {
        val cacheSize = 10 * 1024 * 1024
        return Cache(application.cacheDir, cacheSize.toLong())

    }

    @Provides
    @Singleton
    fun provideOkhttpClient(cache: Cache) : OkHttpClient {
        val client = OkHttpClient.Builder()

        val interceptor = HttpLoggingInterceptor()
        interceptor.level = HttpLoggingInterceptor.Level.BODY

        client.addInterceptor(interceptor)
        return client.cache(cache).build()
    }

    @Provides
    @Singleton
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()


          .baseUrl(mBaseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .client(okHttpClient)
            .build()
    }
}

And my base URL (There's no backend server... could be anything):

<string name="api_base_url">http://192.168.0.12:8080</string>

So, What am I missing? This code should be working...

Any help is welcome!

EDIT:

So, I changed the code to this:

mLoginInteractor = LoginInteractorImpl()
        mServer = MockWebServer()

        mServer.enqueue(MockResponse()
                .setResponseCode(200)
                .setBody(Gson().toJson(User(1, "991889992", "Leandro", "123"))))

        mServer.start()

        val client = OkHttpClient.Builder()
        val cacheSize = 10 * 1024 * 1024

        client.cache(Cache(application.cacheDir, cacheSize.toLong())).build()

        mLoginInteractor.setRetrofit(Retrofit.Builder()
                .baseUrl(mServer.url("/"))
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(client.cache(Cache(application.cacheDir, cacheSize.toLong())).build())
                .build())

And this:

val testSubscriber = TestSubscriber.create<User>()

        mLoginInteractor.login("31991889992", "lala").subscribe(testSubscriber)
        testSubscriber.assertNoErrors()
        testSubscriber.assertReceivedOnNext(listOf(User(1, "991889992", "Leandro", "123")))
        testSubscriber.assertCompleted()

But I still get this error:

Number of items does not match. Provided: 1  Actual: 0.
Provided values: [User(id=1, phoneNumber=991889992, name=Leandro, password=123)]
Actual values: []

Answer

iagreen picture iagreen · Dec 29, 2016

There are a couple of things going on here. First, MockWebServer.url() resolves the given url against the mock server's base url, it does not set the url. If you want to set the url, you'll need to pass it to the start() method. Generally, you configure your retrofit to call the server's endpoint --

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl(server.url("/"))
    // Other builder methods.
    .build();

Second, to get responses from the mock web server, you need to enqueue the expected responses as MockResponses. Otherwise it doesn't know what to send back. Do something like the following before making your request --

server.enqueue(new MockResponse().setBody("Success!"));

You'll need to build your response to mirror the expected response.

See the README for some more examples.