At some point in your code development you’ll want to test how the interaction with your app and the API server is being handled, but testing with a real connection with a server is expensive and unstable. Unit tests should be real quick and assert if your code is working as it should. When you introduce a real connection, many problems can show up: long delay on the response, offline server, API changes that were not supposed to be there. All these can raise problems in your tests that are not on your end. The code you wrote can’t grant that the server will be online, so it’s not something you should be testing in your code.

So, how to solve this? The answer is simple: simulate a real server connection with the expected responses, for which you know how your code should behave and what’s the expected result. For this, I’m going to show a very simple usage of MockWebServer that can give you an idea of how to use it in your own tests.

Setting up the dependencies

In this demo I’m going to use the following dependencies:

MockWebServer: The very reason of this article. It’ll be used to simulate a real server api with the responses we set. Retrofit: A very known library that will be used for making the requests with the fake server. Moshi: Deserialization library to transform the JSON responses in objects.

These are the dependencies needed to be added in the code:

testImplementation 'com.squareup.okhttp3:mockwebserver:4.6.0'
implementation 'com.squareup.retrofit2:converter-moshi:2.8.1'
implementation 'com.squareup.retrofit2:retrofit:2.8.1'
implementation 'com.squareup.moshi:moshi-kotlin:1.9.3'

Some help

For this demo I’ve created a Helper class that will make some things easier for us. I won’t talk about details of what it does but if you’re curious you can check the comments in the sample repository.

Preparing the tests

The first thing we need is getting some instance of the MockWebServer and starting it before and shutting it down after the tests, we can do it like this:

class MockWebServerExampleTest {
    private val mockWebServer = MockWebServer()
    @Before
    fun setup() {
        mockWebServer.start(8080)
    }
    @After
    fun shutdown() {
        mockWebServer.shutdown()
    }
}

Simple, right?

We also need an instance of the API, you can get it on this demo like this:

private val api: Api by lazy { generateRetrofit(mockWebServer).create(Api::class.java) }

This uses a method of the Helper class I’ve added in the project, so make sure to check it out to fully understand what’s happening but basically we are just creating a instance of Retrofit using our fake server and getting an instance of the Api class where we have the endpoints.

Setting up the responses

After we have the MockWebServer instance we now need to add a file with the JSON response we want the fake server to return. For this you need to add the following command in your build.gradle:

android {
	...
	sourceSets {
		test {
			resources.srcDirs += ['src/test/resources']
		}
	}
	...
}

This will make sure that we can find our response file when running the tests.

And now we can add the actual response we want in the assets folder. I’ve used the posts placeholder from the JSONPlaceholder website.

So it will look like this:

[
	{
		"userId": 1,
		"id": 1,
		"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
		"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
	 },
	{
		"userId": 1,
	    "id": 2,
	    "title": "qui est esse",
		"body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
	},
    ...
]

Add it to the src/test/resources folder (create the folder if you don’t have it). You can see the final content of the file here.

Testing

After setting everything up, we can actually start to write our tests. In this first example we will make sure we have a success response and that after running the test the response file was actually parsed and the list of posts are not empty.

For setting the fake response, we use the following method:

mockWebServer.setResponse("response.json")

Success

Noticed that response.json is the file we added to the assets folder which contains the response we expect from the server API.

The full test looks like this:

@Test
fun `Get Post List Should Not Be Empty`() {
	// Given A Post List Request
    val interactor = GetPostsInteractor(api)
    // When Executing The Request
	mockWebServer.setResponse("response.json")
    val postList = interactor.execute()
    // Then Posts Should Not Be Empty
	assert(postList.isNotEmpty())
}

Error

In the perfect world we always would have a success response from the API, but on a real production environment many things can go wrong: no internet connection, long latencies on response, wrong response from the backend.

Having all this in mind, we need to verify if, when something wrong goes with the API, the code can handle the situation the way we expect.

For this we are going to run basically the same test, but this time returning an error response from the MockWebServer. We can use the following method:

mockWebServer.setResponse("response.json", responseCode = 404)

We set the response code as 404, so the request won’t be successful.

The final test look like this:

@Test
fun `Get Post List Should Throw Error`() {
	// Given A Post List Request
    val interactor = GetPostsInteractor(api)
    // When Executing The Request
    mockWebServer.setResponse("response.json", 404)
	try {
        val postList = interactor.execute()
        assert(false)
    } catch (e: Exception) {
        // Then An Error Should Be Thrown
	    assert(true)
    }
}

Notice that this time we only asset(true) on the catch as we are expending our code to raise an error when it’s not a success response. If it runs even with the server returning 404 then something is wrong and we set assert(false) so the test fails.

Conclusion

This is just a simple and quick example of how you can use fake servers to test your code implementation. The MockWebServer is way more powerful than what I’ve shown here, so make sure to take a look in the GitHub repo for a more detailed use of all its features.

You can also take a look in the sample repo where you can understand a bit better how everything works together.

Article photo by Taylor Vick on Unsplash

Author

Tiago Araujo de Souza

Android Developer

Always trying to early adopt as many technologies as possible 💻

You may also like

Let it flow

I’ve been working with Flow on production for almost a year now. The light weight kotlin coroutines stream library has completely replaced RxJava for our new projects. RxJava is still a trend for Android Development even in 2020. But this article is not another RxJava x Coroutines. It is here...

Alibaba Seata

Seata is an open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.