Tech Showcases,
Developer Resources &
Partners
droidcon News
Fake it till you make it - effective use of test doubles
By
Jarosław Michalik
droidcon APAC 2020
Test doubles are powerful tool in developer trying to write unit tests. Mocks allow us to keep system under test isolated so we can check given scenarios and perform assertions on singular piece of logic with ease.
In this talk I will dive into fakes, mocks and other test doubles and I will present use cases for each and every one of them. Also, I will share my thoughts about mocking frameworks and give some tips & tricks of how to use them with ease.
Transcript
English
00:10
hi everyone i'm very excited to be here on droid con online events i always enjoy droid cons offline and online but this year we attended online conferences so that's the situation but let me introduce myself at first most of the time i work on android applications with tango digital agency in krakow in poland and besides that i do some freelancing projects that are worth extra time i write blog dedicated to testing with kotlin and kotlin testing related tools my sport activities are focused on volleyball both indoor and pitfall and i also create music if you are interested you can hear my work my beats on spotify and other popular streaming services link to that stuff is aggregated in the link you can see on the screen on social hub available also on the query code but let's not forget why we're here we are here to talk about the fundamental concept of unit testing test doubles i will share my thoughts about unit test and especially using test doubles for better and more efficient mocking
00:15
here you can see the test pyramid which is some kind of graphical representation of how test suits should be designed in process of software development on the top we have ends to end tests in android case that would be automatic ui test using frameworks such as espresso or appium stuff like that the second stage are integrations tests in this case we could be testing integration between elements basically integration between high-level components in android we could use libraries such as roboelectric to mimic some system behavior or even trigger some actions on views and on the bottom of the test pyramid we have units tests tests that are performed in isolation are relatively cheap and should be running fast
00:20
and usually in software projects there should be more much more units tests that any other kinds of automated verifications
00:25
and unit tests and ways of keeping isolation is the main focus in today's presentation let's take a look at this puzzle they represent some kind of software system where each puzzle is some component as you can see they are somehow connected while we are focusing on the class we want to test
00:30
we should stay take care of its direct dependencies marked in yellow and in units tests we don't care about other components that are not strictly bound to the system under test
00:35
so let's break it down a little we have our class a system under test and some components that are its dependencies usually passed in constructor we won't pass the whole dependency but try to somehow provide a test double object which will fit right into particular puzzle in a convenient way
00:40
and i have android background and i believe most of us are android developers so let's try to present test doubles in android context in android apps we usually have some kind of splash screen displayed right after app is opened in this place we should decide if user should be redirected to the main screen of the app or show him login screen and splash screen dependencies are hidden behind an interface we have router which is responsible for opening given screens we have interface for view such as activity fragment or custom view where we would display error or trigger loading indicator we have also use case which will tell us if user is actually locked or locked out into our app and last we have some property for analytics this could be example for example string representing some advertising campaign from google play or other stores stuff like that so what should we test here what should be tested of course stuff like displaying loading indicator if our presenter is triggering router to go to proper places and finally verification if error is displayed when something in the logic of the presenter goes wrong so let's see how it fits into our puzzle and decide how we should create test doubles to have splash presenter isolated
00:45
let's take care about first dependency of splash screen presenter splash a real implementation would start activity change something on a fragment manager or trigger something in the navigation graph with navigation component and in the test double we want to know if a given function was invoked so we could perform assertion on that
00:50
and another dependency view android implementation would be directly bound to the layout in xml it would be changing visibility of some loading indicator or trigger snag bar event for example and in our units test we cannot mock the whole activity on fragment so we need to provide test double some kind of object that will record its interactions or somehow store the whole state of the screen okay next dependency use case this class would check user existence in local database or simply check token validity then reduce that information to anom class indicating if user is locked in or locked out and in our fake implementation we will just return given enum values or throw exception to simulate real system behavior and finally tracking id in real application that string would be passed from external application or external component and in unit test we can directly provide fake value
00:55
so now we are ready to distinguish some kind of test doubles we have stop which will be used to return predefined value we have fake where we would create some lightweight implementation for our dependency we have mock where we would be storing information about its interactions and we have dummy value some property we pass to units test just to satisfy compiler but we won't take care of it and it's good to remember that we often call all test doubles mocks so now let's see how we can create mocks for each dependency in our splash presenter let's start with resolve user state use case it is interfaced with one method so we can return values directly it is also kotlin functional interface so this could be done in the single line in lambda and we could return state logged in state locked out
01:00
or just draw exception from that method
01:05
next thing similar to stop could be dummy value but the difference is dummy value is not used in that particular test case we we often don't use it we pass it just to have build passing
01:10
we have mock we want to somehow record interactions with splash router and we can use here mocking framework such as mokito to verify if given method was invoked
01:15
and we can use stuff like mokito to perform assertion we create router with mokito and then verify with mokito function verify if this method was called and of course there is opposite case when user is locked out we expect to open login screen instead of the main
01:20
screen and we can also provide mokito moc for view in case of exception thrown by resolve user state use case we want to display error on view and thanks to makito we can perform this verification in single line too
01:25
yeah that use case throws error and then with mokito we verify that the display error method was invoked on a view created with mokito
01:30
but it's good to remember that we are not bound to mocking frameworks we can provide our own light with implementation by ourselves and good example would be the view of that splash screen somewhere in the test directory we create an implementation for that view interface which will keep the state of loading indicator and record information that error was displayed so in that case when in our test we throw exception
01:35
and the display error was properly properly invoked on view we can simply check if our fake started was changed and instead of using mokito for verification we perform simple assertion on property in our fake object
01:40
so effectively what are the differences between mock using framework and custom fake mock can be created for us by framework such as mojito mokukei and for more complex cases uh of course we can configure this mock to create more complex objects and we can of course use matchers i will show the example later to verify how many times given function was invoked and with which arguments fake in the other hand has to be implemented by you by the developer in non-complex cases such as a splash screen as shown before it just implemented interface and adding some boolean properties to this fake and you are in full control in here you can decide how this fake should behave and effectively you can reduce complex verification to simple assertions as shown before an example
01:45
one of the most popular mocking frameworks for jfom is mokito it allows creating mocks in a simple way even in one line and i will present usage of mokito with mokitoklin extensions so let's consider another screen with viewmodelpresenter architecture we have some view which will display a list of items we have data source such as database described by interface with two methods get all elements and get one element by id and we will use mokito to create stop for data provider and to create mock for view
01:50
so let's jump straight into the first test case we want to verify that if data provider returns non-empty list of elements then all that items would be displayed on film so first we create mock for our view
01:55
then we create mock for data provider with proper stubbing on get all method invocation we will return given list of elements and then we are starting presenter and using mokito function verify so we could check that display items was invoked with that given a list of elements
02:00
that was pretty straightforward example so we could do something else another test case for that press enter could be verification of displaying only one element and here we have stop for another method of data provider get one with mokito we can stop a very specific method invocation we write that on get one method with any parameter it should return given element any is here example of matter this method this method would be stopped for all possible invocations excluding null values because we have separate methods for that and then with this configuration we can proceed we can proceed to regular verification on view with mochito we verified that display details function was invoked with given element that was returned by mocked data provider and we can introduce more complex matters if we need to let's suppose that we want to return always the same element for faction invocation where id described by integer value is between zero and five and we could use mokito matcher arc dot in that lambda we write boolean expression and while performing stabbing mokito will check that that's bullying that bullying lambda and will return given element for elements matching this expression and for function invocation where id is higher than 5 it will draw exception and matchers can be used for verifications too
02:05
in this example we can use similar matter in assertion in verification on display details
02:10
and make the test pass for every argument that matches given boolean expression especially in this test case for that argument which content is equal to string first
02:15
and that's not everything that mokito can do for us we can perform other essential assertions and verifications as well and now we are testing path where the data provider return new value instead of valid element and then we want to verify that error was displayed on view and that display details was never invoked with any arguments we have special functions for that kind of stuff too
02:20
and of course all of those things could be achieved without using mokito for every test case we can provide our own lightweight implementation and create custom fakes this may be convenient when we are not sure how a specific mokito matcher should be used in here or we would really need to stretch the smokes to really mimic behavior in tests we to meaning this behavior we want to achieve and in general there is no silver ballot for creating test doubles and every test case is special in its very own way and also we should remember that mokito is java framework and especially nowadays in android work words we use kotlin
02:25
and unfortunately kotlin specific feature core routines are not directly supported by mokito when we will try to mock suspend function with mokito test codes simply won't compile in that way we could of course try to use generic mokito mechanisms such as do answer construct but we could lose readability of this domain specific language and there is another there is another framework for that that we could use this is mock k mock k is scotland first library with dsl style stepping mechanism and with built-in coroutine support
02:30
with mock k we just write c o f from coroutines i guess and create stabbing in a similar way that we would do with mokito but our routines are supported i believe we will have at this event another talk about mokuke so you should you should see that talk if you want some details about mock game
02:35
and there is of course other solution for mocking suspense functions we could just create simple fake instead of relying on framework we can implement that interface if it's convenient for us and implement that given a suspend function with our stopped data
02:40
okay next thing static properties in java and in jfom libraries are very common some developers love to use static constructs while other are criticizing every aspect of static keyword that's not for me to tell if static is good or bad it's a tool it exists and i will show you a few approaches to handle static access in test code
02:45
but let's check again our puzzles with system under test dependencies static objects are not direct dependency of system under test in a way they are part of it as well they are kinda outside
02:50
and the most straightforward way to include in a reasonable way static dependency in test is to removed is to remove direct static access if you need to change behavior of some property in test you could just use extra interface or facet to abstract it away first example could be using date time dots now method from the other time
02:55
we have our code relying on the other time and we use it uh in a abstracted way we create provider for data type we execute uh in our system under test this wrapper method and we can easily mock mock that interface and other case that developers using rxjava may be familiar with is abstracting away every scheduler we need to use in a system under test and injecting that facets into presenter or view model that's i think the best example of using proper to remove static access in test code
03:00
and sometimes static methods are invoked underneath who just like it could be in live data some kind of approach of live data using android mine thread under the hood could be delegating main thread executor and setting its value before we execute our test suite and releasing it when we're done this before spec and after spec are callbacks from from co-test specifications before spec will execute just before we execute our first test case and after spec when all test cases are are run
03:05
and of course for mocking starting fix we have library mock k actual actually allows us to mock static things for one of my pseudo integration tests for data binding i used mock k to mock android looper and that's possible should you do that probably not but it's a way you could you could hack some things so how can we approach testing static things if you can remove static k word and then rewrite particular piece of code that's great just do it and if that's not possible and you should depend on that static access in your units test try to at least create provider or a little abstraction for that and if this fails check if you could set something globally you could globally probably set date time dates on stuff like that and if other things failed you can use smoking framework to do the hard work for you you can use mock k power mock power mock was popular in java when i was developing android apps with java and of course if you are brave enough you could try to use reflection to modify existing properties in runtime and then use static objects in your test with proper configuration
03:10
and sometimes library developers also provide some test extensions for for methods that they exposed in a static way so you probably could use that
03:15
okay to sum things up we talked about fundamental concepts of unit testing test doubles and in the end i want to give you a few takeaways know your test structure with given when then flow you will find creating test doubles much easier in the given section prepare dependencies for your system under test configure steps in one section exact logic you want to test and in the end compare your results your system under test generated to your expected output
03:20
know when to use proper test double sometimes you only need to pass stab the value or simple fake so there's no need to use mokito or mock k for that don't overuse mocking frameworks using mochito just to return predefined value could be overkill for your system and when you have very big tests viewed it could lead to performance issues and sometimes it's easier and more efficient to write fake yourself and last but not least keep good separation of concerns or at least use constructor injection it's not impossible to provide fakes for static variables and objects but readability comes first if your code is solid and in general follow dependence inversion principle then you are good to go with writing great test suits that will serve you your team and your project very well
03:25
so thank you for your attention that's all from me today i hope that you enjoyed my presentations and for more units testing created content you should check check my blog kotlintesting.com if you want to find me online go to the link you see on the screen ping me on twitter and i am open to discussion i think we can we can start qnt
03:30
uh
03:35
okay we have anonymous question should we prefer fakes over mocks if yes is there a way to use fakes without interfaces interfaces that are needed just for testing seem like too much effort to justify it example use cases in presenter's view models okay should we prefer fakes over mocks it depends on your use case of course and in general your programming style probably you don't want to use mokito for everything and also keeping a custom fake with for a single first single method for interface or class with single method could be more efficient in that way
03:40
that's it actually lets you write production code in more solid way good tests will will suit very well codes that follow dependence inversion principle and other principles defined in solid so should you use interface for everyday use case probably yes i think uncle bob would say yes but in a real situation it depends on a specific use case every test case is specific and very special in its very own way have you use have you do some runtime benchmark between using fake and mock no i didn't um what strategy should be used for private methods well first of all you shouldn't be using private methods you shouldn't be of course you should be using private methods you shouldn't be testing a directly private method you should be testing a private method interactions between your components you don't want to test if
03:45
some internal state changed in your system under test you should rather test output and input of the whole units in units test and that you need could be parts of your presenter part of your view model but in general don't test private methods test private methods interactions with other components and to see if actually you have tested somehow private method you could check code coverage for for that stuff for contacts for content resolver testing should we mock or make fakes and if we mocked what framework should be used
03:50
well lately i used content resolver for something i can't really remember but i remembered that i created the whole adapter for resolving that stuff so i wasn't directly testing content resolver uh content resolver objects
03:55
verify objects uh private method can this be done
04:00
i'm not sure if it can be done directly i know that makito has some hacks built into but i believe if you satisfy compiler you could make that verification with reflection
04:05
if you are brave enough no reflection and or just want to have fun with hacking stuff on android and j41
04:10
okay no more questions thank you for hosting me and see you on the other side of the stream
04:15
bye
droidcon News
Tech Showcases, Developer Resources & Partners
EmployerBrandingHeader
jobs.droidcon.com
![]() Latest Android Jobs
Kotlin Weekly
![]() Your weekly dose of Kotlin
ProAndroidDev
![]() Android Tech Blogs, Case Studies and Step-by-Step Coding
Zalando
![]() Meet one of Berlin's top employers
Academy for App Success
![]() Google Play resources tailored for the global droidcon community |
Droidcon is a registered trademark of Mobile Seasons GmbH Copyright © 2020. All rights reserved.