I am a software developer at uber and today I am going to talk about UI testing mostly about expresso cool so the things we are going to cover in this talk is basically expresso basics and then some of the recipes we use express we use internally at uber to write more reliable expresso test and what are the things we can achieve with expresso cool so these are the things we are going to use one is expresso itself with gradle build variance ok sttp we are going to use dagger 2 just a little bit then ui automator and screenshot test I am not going to cover today so basically first I want to discuss what is UI test and why do you need it so test this is a test funnel it is proposed by google what it says is that you can break your test in three different test cases one is end to end the other is integration and finally you have unit test and what this suggests is to write 70% unit test 20% integration and 10% end to end test so why do we need big test like why is unit test not good enough so these are the issues first of all unit test is fast same same whole true for integration test also like they are fast they are reliable they isolate failures so because you are just running a very small feature the failure you can pinpoint the failure itself but the only problem with unit test is that they do not stimulate a real user like even if you are using unit test on android you must be using robo electric which is just a shadow of the actual framework so yeah I am going to talk about expresso mostly in the integration test I am not going to discuss about end to end test because there are just way too many caveats there just many points of failures and yeah you make actual network calls so yeah just too many points of failures cool so expresso is a very simple API very simple fluent API what it shows is on view you provide the view measure and then you perform some view action and then you check the view assertion so yeah here is a life changing app what it does is that when you click the hello world button the button gets disabled so first what you do is that you find the hello world button itself and that is what with id does that's the view measure it locates the view within view hierarchy so with you can send the resource identifier r.id.hello world and it gives you the hello world button what you did next is you can do next is that you can click the button itself and then after click once the button is clicked it can be any other action also like long click scroll miss unless you and then finally you can verify that the button was disabled after the button is clicked and that's why you can make sure that nothing is broken in your production app so view assertion basically asserts the current state of your screen of your UI so the next thing I am going to talk about is rules these are simple junit rules how many of you have used ever used rules like before and when you're writing junit so rules are really powerful way one sample rule I want to show you is temporary folder so once and you can use multiple rules using changing so what this rule does is that when you write a test inside this test when you create different files once your test ends this rule temporary folder delete those files so you are clearing up resources and you don't have to write tier down so rules are really great if you want to use an object in global scope modify it and then in tier down you don't want to take care of clearing this state and example is like let's say you are in you have an AB test manager a cat mark AB test manager that's in the global application scope and what for a particular test you can write a rule AB test rule and a proper for a particular test what it does is that it puts that AB test in treatment and once that test ends it tears it down and you don't have to write it yourself so yeah it adds basically behavior and runtime cool so I want to show you how to write a custom rules and even have written custom rules no one okay so yeah you can use you can write custom rules it's very simple to write first you define a custom annotation we call it annotation X and then you can write so you can just extend test watcher this has this test class have two simple methods starting and finished starting gives you an object description from which you can get annotation you can inject your AB test manager here you can change the state AB test manager dot put this experiment in treatment and then in finish you can clear up your state so why am I discussing it because I'm gonna you I'm going to use it to mock network right to label UI test cool so one really handy tool I want to show you is UI automator we talked about we talked about the fluent API express a fluent API here can be there can be a catch here what if the button is not enabled but it's not visible like something or if the button is not clickable and it was in fact of disabling the button we actually make it unclickable but both look similar like on UI so how can we check the state of this button this is simple tools it's available in the SDK slash tools folder of Android automator viewer and you can go and check the state of different views just to point out when you're writing UI test you are not writing it for testing your code but you are testing the actual user functionality so you don't have to know you don't have to see the actual code base what you can do is that you can open up your app in this UI automator viewer you can check the state you can check the resource ID is also there and you can write simple UI test based on that not only that you can actually write UI test for other apps also like not using express so but but using automator viewer is like one thing cool so the final basic thing I'm going to talk about is custom viewmatcher so we discussed about viewmatcher when we were saying on view with ID and we find a viewmatcher with ID which helps you find a view with resource identifier what does this custom viewmatcher does is that let's say if you have a text view and you want to find a text view with compound variable r dot variable dot back button so what you can do is that you can write a custom viewmatcher with returns a bounded matcher is a bounded matcher on text view so what it does is that it finds all the text view in the entire view hierarchy and then it have a simple method matches safely this matches safely method I try to all the so it gives you all the text view so this method runs with all the text view in your code it and then you can iterate over all the compound variables and find if the resource variable matches like if this text you have r dot variable dot back button if it does then you can return through otherwise you can return false so once once it filtered out you will get the text view with compound variable cool so this is a cheat sheet I'm not going to discuss more about it we already talked about with ID there is with text is with hint if you are using a text they are view actions click long click scroll for list view like if you have a login view and if that view is controllable and if you have to click button maybe you have to scroll that view before you can actually click that button you have data options those are used for list use with you assertions we talked about we talked about matches and there are so many other things so yeah I have added links to all those resources cool so I'm going to talk about recipes now these are the more interesting things so first I want to just give one page introduction about will be in so they'll be in can be different flavors it can be released the actual thing you upload on a store it can be debug it can be test it can be mark it can be internal you can switch different I mean you can switch different configurations if it's released maybe we make we can enable our crash analytics or criticism you provide if it is debug then maybe we can just disable SSL and because we want to see the actual network log we can enable stetho so most of our code we are going to discuss today is going to live in is not going to live in release you can put it in debug test mark internal like something you really don't want the actual user to see also so I'm gonna first talk about how can we write more reliable UI test for network so this is an action this some app which is making a network call it's hitting cloud which is hitting some data source something so there are many issues first of all hitting network first is timeout your network call may timeout and then it's again memory intensive anyone here can who can point me out what can be any other issue when we are actually hitting the actual network call one really important thing yeah I guess I can just talk about it so what if you are using a network request which changed the state on cloud so let's say if you have a user so we are testing a functionality where a user have taken two overrides and we are making a so uber took his and now we are testing a code which tested right right flow and we made a network call which increase the right number of rights of that uber from two to three if you know that thing is changing state so if you are using actual network call and you are getting the this request you're getting the response the next time you're gonna get three right and so you cannot write reliable UI test if it's changing state so so for fixing timeout Xpresso gives a very handy tool it's called idling resource so by default Xpresso synchronizes on main thread so it waits for it waits for all the activities on main thread to finish before it actually starts testing that's a big advantage over APM and other framework so Xpresso how can you synchronize background thread what you can do is you can use something called counting idling resource and before you start a long task you can increment the counting idling resource and after the long task is finished you can decrement it once you're counting idling resource value is equal to zero that means all your all your tasks you started are finished and then you can just register it so once this count equal to zero Xpresso will start testing so this is for this I'm showing an example for schedulers sorry for executors if you use Rxshawa you may have used schedulers from the dot from executors this is synchronized even for that they are custom hooks for existing Rxshawa schedulers also you can just go ahead and have a look so if I want to synchronize something on threadpool executor that I want to make sure that until and unless this threadpool execute the task on this threadpool executor is not finished I don't want to test so because I'm making network call or I'm actually loading data from DB on from this thing and I want to make sure that all those tasks are finished so before you start task you can in the execute method you can do thread count plus plus and after the task is executed you can decrease the thread count and when the thread count is equal to zero you can just this callback dot on transition to idle so what it does it does it does do the same thing which counting idling source does like once you have thread count equal to equal to zero that means all your background tasks are finished and you can now start doing UI testing cool so this week's the timeout related issues but we are still hitting the actual network so state issue is still there and also in a big app like production app like uber we made many net we made actually many network calls and imagine and we run our tests every time some user push send some some code review or a push something so if even if you are sending like 100 or like let's say 200 code reviews are day and if we are if we are making an actual and if if we have like let's say around 100 tests and each test is making two or three network calls then it's also like 100 into 2 into 200 so we are making like thousands of network calls which are redundant and which are actually hitting our server it's even more important for startups because server is so costly like I have used it pass and I can tell you it's very very expensive so what you can do is that one when you are writing the test you can record all the you can record all the response and you can store it in a file you can cash it in a file you can you can commit that into your gate repository and when you are running that test on the on ci you can just replay that so it fixes both these issues first of all you are not not not making those hundreds and thousands of calls and also it's a stateless like if you have if the customer had taken two trips before like since we are reading back from cash he had taken two trips every other time also so I'm gonna use interceptors so and if one anyone of you have used interceptors here like for something anyone of you who are using authenticated request in your app like android app like we have password user session and all those information not many okay so yeah if you are using if you are using authenticated request the best way is to use interceptors what interceptors does is that it modify all your network request so if you want to add some header or something to your header or something you want to add to your all your network calls the best way is to use interceptors interceptors intercepts all the network calls so it takes an interceptor or chain you can get the request and you can modify the request in some way like you can add retry I'm pretty sure I mean I'm not sure why are you guys not using retry the best way to do that is to use an interceptor so yeah you can get the request and you have a method chain proceed which which actually helps you make the actual network call and and then you get the response so first we are going to discuss about record interceptors so record interceptor what it does is that when you when you are making an actual network call it helps you record the network response so you made the network call you got the file name the request URL and you serialize the response and save it in your file it's gonna store it in your gcard all you need is a permission to write external storage you can pull this file and you can commit it to your gate repository and then when you want to test something you can just write a very simple rule add replay record equal to true so when you did record equal to true in your starting of rule you can read this thing and you can switch the interceptor to record interceptor when you want to run it on CI you can just get rid of record equal to true and it will run in replay interceptors and replay interceptor does nothing instead of making an actual network call it just needs from the file you saved in your assets that's it so now yeah now you are not hitting the actual network and you are just reading from the cool so this is the star of this talk robots how many of us use structure some kind of structure in our code like MVP MVVM like yesterday there was a great talk on that all right many much so and how many and do you guys use some kind of structure for your test case like when you write J unit some kind of structures anyone who here you okay the one so robot is a pattern it it was it was a given in a tech talk by explain a tech talk by Jake Wharton in Kotlin nights and we call it internally layouts it's a slightly different variant of what Jake Wharton talked about so this is really cool it's just gonna like reduce your test class by some some some multiplier so let's say this is an app which accepts an email address word bar.com and once you click the send button it shows you success but there can be many other cases like if you write through and you click send the email address is not valid and shows you a failure another thing is if you have an empty text and you type send it's again a failure let's say you have some many more other cases you don't want to get a phone the app and the text should not start with a number or you don't want to support Yahoo I mean it's not that great so so yeah what so for testing it what we are doing is that we are writing a view matcher on view with hint we are writing the foo at bar.com and then we are clicking the send button with text or perform click and then we are using we are checking the if the success is visible or not similarly here we are typing text foo and we are clicking the send button and checking if it failed or not similarly so if you if you notice like we are repeating code three times and what if what if someone changes to recipient text tomorrow so yeah I have to go and make this change in all these three test cases so the solution for this is a robot it's kind of MVP for UI test or unit test or you can use it anywhere what you can do is that you can extract out these lines on view with hint recipient or perform type text and you can take text as an input and you can extract it out in the first one payment robot recipient and you can pass foo at bar.com foo here itself and then you can write similar methods for each of those and then you have a result robot result robot is success just check if the success text is visible so you can just you just now got a fluent API you can write payment robot dot recipient dot send and you can check result cool the last thing I'm going to talk about is testing because all of us are writing for apps for India and we have really we don't have great network in smaller cities and we also have phones like not like actually in access one but yeah so I just want to show you a list view and a horrible implementation of list view so what it does is that it in place they list you every single time and it finds the view also every single time no view holder anywhere and it creates a bitmap also every single time no glide no Picasso it does not reuse bitmap it's very very bad and we can we can use Expresso to identify like the issues in our app so what we can do is that we can call list view dot smooth scroll to position and the end position and before it runs if your phone is not decent enough it will definitely crash so and then you can similarly use rules Expresso have several rules which you can use with monkey runner that's a you can go and check it online so one rule is test tracing post test jump this lock at helps you find the lock at and next set give you your net history so you can use the test tracing tool and that test tracing tool what it does is that it generates this is trace for you so if your app crashed you need to trace to identify what is the issue so this is this trace and I it shows me I loaded in Chrome it shows me the issues with this so it shows me expensive bitmap uploads the other F was the measure time was really big there was another F which was saying that I'm inflating view way too many times probably I should use you hold us so yeah you can run it on CI you will get the cache you can open those things in your cool so here's a conclusion use UI test to identify how your app looks in front of actual user the network replay record is really important because it lessens the burden on your expensive servers use robots it helps you write much much less code and much more scalable test and finally use the performance section of Xpresso it's very important because you have phone segmentation huge phone segmentation and network is also not that good that's it any question hello hi yeah yeah so I've been using Espresso quite a bit along with cucumber to do my BDD test so I've used I know Espresso is mainly for within your app so something apart from your app pops up like you use or probably use UI automated for something like a dialogue that comes up when you're running new guide or something like that but what about push notifications do we have something to take care of push notifications that's a big catch so the problem with push notifications is you cannot intercept I think there is some solution but I'm definitely I mean inside in that Uber but I'm definitely not aware of it like all those replay and record things they only work with the polling solutions HTTP HTTP to kind of thing but definitely not okay so that that part of is usually not tested by so I mean one way I can think of is to write your own so when you're sending push notifications you can write your own mark notification but the only problem with that is that you cannot control the time when it's gonna come like your pushes usually you don't you don't control that thing so you can write your own mark notification provider which can fire those notification okay and if you are not testing it if you if it's not if it's time independent then that's great it was for you and if you're writing push notifications in a way that's time dependent then definitely something is wrong okay thank you so in a special how do you measure actually by number of lines you cover or by the number of cases you cover so usually it's so it's not so number of cases can be two things first of all it can be number of cases based on your code base like if you have written in if cells you want to call probably both itself but in express so I'll definitely search not to do that you do that in the over electric unit in express so test all your customer-facing use case like if you have two or three feature right different express so test for those two features don't write it like point itself case so yeah my recommendation is don't ever look at your code when you're writing express so test you don't even need to you can always use your automators you are and you can write your test accordingly we are talking about we should cover number of lines it's so coverage is I think as a concept in express so I really don't know if I can actually map it like it's completely different to J unit so I don't have a very good answer for this like how what how do you measure it but definitely I mean I don't see a point of like coverage and the whole thing suppose in any activities we make a network call on on create yeah so how do you do by making extra other another activity for it or you'll kind of a stub activity or sorry can you repeat your question suppose you're making a network call on on create method how do you measure it how do you do how do you delete sorry what is the method call back are you saying are making network call okay so yeah you can usually do the synchronization they provide you if you are using our extra like some existing library like if you are using an executor service you can synchronize that by using the counting idling the source if you are using an async task you are automatically covered by Android like loaders in async task express so automatically synchronizes on that thing just to empathize one more thing express or actually start the start the actual app so this I mean I thought more over it and I mean I cannot think of like the concept of coverage in express so last question hi so you must be doing a lot of testing around location yeah how do you do that rules again so you can write a rule location rule at extents rule inside this rule if you have a location client you can set that and then inside and you can take so I showed you rules right before the custom watcher thing so what you can do is that and inside with annotations you can also pass value yeah so with annotations with annotation X you can actually pass value like I need 23 Fahrenheit sorry I need 23 degree light 23 lightitude maybe 66 longitude and I want that only these ubers will be only these type of ubers will be available so what you can do is that you can pass all these values so I mean I don't work on anything specific to that but and I don't know if it's the actual way if it's the exact way it's implemented in Uber but I mean I don't see a reason why it will not be a rule like the best part is in your finished all your locations are cleared and you don't have to tear it down every time so your your UI test will be like really level okay so you're saying that for all instrumentation is possible such as GPS Bluetooth NFC Wi-Fi we can have rules for all of them right yeah you can definitely have rules for all of them yeah you can just change you must be having some some something like observable or some iterable which is which you are reading like you have a location client you connect to that and then in on connected so you can actually change that location client inside this starting and you can make it a bit event here you show some example of such I can discuss it definitely like I can show you an example of that not in Uber but outside I have seen someone using it that way okay I'd like to see that thank you sure thanks everyone will be closing questions now because we're running a little late we're off a break right now but we'll resume at 1150 exactly so please be back thanks