
Integrating MockWebServer into production project’s UI tests
UI tests is something that your team have to face eventually if your project is growing and regression testing demands more and more QA team resources. And usually it’s something that is not taken into account in the beginning of the development process so then you have to deal with, maybe not the worst architectural decisions that were applied in your project, but some that might slow you down your pace on the way to bright QA-free regression testing. In this small paper I’ll try to cover both dealing with such issues that you might or might not have in your project and integrating of MockWebServer into you production project’s UI tests.
Why MockWebServer
So, I like to think of UI tests as of a mean of testing that some changes in project’s code haven’t broke UI behavior or that some new feature behaves correctly for the given BE responses (success/error) and thus they should rely on stable BE behavior. Usually you have some kind of BE test layer located at some https://staging.yourawesomeapp.com
endpoint and since it’s a testing environment for your whole team then it’s not reliable to behave as expected at any given point of time.
Here comes a MockWebServer to the rescue. That great framework allows you to test any BE behavior scenario that you could think of with 100% scripted mock of your web server (who could have thought).
So, lets start with the rule that we’re going to use in order to supply mock responses:
Before we go line by line on that it worth noting that above usage of mock server was suitable for my purposes but usually you would like to wrap the original statement with try/finally
construct in order to shutdown server once base statement was evaluated.
BASE_URL
If you have long running production project then chances are that you was not counting for ability to substitute base url of your app by DI or any other means, so you, most likely, do have something like this somewhere among your project’s build.gradle
files:
So, in order to add the ability for using MockWebServer’s base url we could use some framework like MockK
to mock static BuildConfig.BASE_URL
field value or add check for custom command line launch parameter to substitute this field in build process. I decided to make it simpler and do the following:
I prefer this method in order to have an easier way for developers to switch for UI tests environment and having obvious separation of environments for CI scenarios (run UI tests on mocks for verifying that new feature haven’t broke expected app behavior and on real staging environment for pre-release regression testing).
Mock Models
As you can see I use MockModelWrapper
set and pass it to MockDispatcher
in test rule’s constructor.
As you can see it’s a simple class to hold two entities markers
by which we’ll determine responseModel
that have to be used by MockDispatcher
.
Let’s take a look at RequestMarkers
:
It’s just a simple class with 2 fields to help us determine where to seek for mock response when our mock web server receives new call.
Note: this structure was suitable for my project and you might reconsider it based on protocol that is used by your BE.
I guess it’s straight forward and requires no further explanation so let’s move to MockResponseModel
:
Couple of things, worth noting here :
asMockResponse
transforms this structure into suitable for mock web severMockResponse
retryAttempts
is just a map where key represents attempt number (yeah, we could use list but I like having a bit more transparent signatures). I decided to use such approach for cases of repeatable requests with same signature but with different response behavior required by test cases.
Now, having this models let’s have a look at place of their actual usage, MockDispatcher
.
MockDispatcher
So, let’s go step by step and understand what’s going on here.
In constructor we simply transform set of mock model wrappers into httpMocksMap
to search then for response models by request markers.
Then, once MockWebServer records a request we transform it into our request markers and search for appropriate response model in mocks map. If we find one then we use corresponding retry attempt response or default one if none found.
That’s it! The only thing left is some base test case where we apply this rule.
BaseTestCase
So, here, as you can see we just check for ability to use mocks and add it to our rule chain if possible.
MockModelScope
is just an interface to restrict usage of mock entities (such as fullAuthMocks
).
That’s a wrap. I hope that this small article will help you somehow on your way to automated QA process.