Advanced Espresso – Google I/O 2016

Just another WordPress site

Advanced Espresso – Google I/O 2016

So who’s excited about testing? [CHEERING] Excited? Yeah OK, how many of you are testing your apps already? [CHEERING] Is there anyone who is not testing their apps? [BOOING] I don’t believe you Unless your apps are not working So, yeah, testing, Android testing There’s been a lot happening during the past year, past two years in Android testing We’ve been getting better and better at this There is now great support in Android Studio and Gradle to run your tests There is the Android testing support library It’s an unbundled library It’s unbundled from the framework You can update it with a support library It’s always fresh That’s a good thing And one of the pieces of this is Espresso, our UI testing framework, which you probably all know about, since you are all testing your apps But that’s the part that we’re going to concentrate on today So, yeah, Espresso– just a quick recap, quick intro for maybe those of you who are listening on the live stream who are not Espresso experts yet, I want to discuss the basic Espresso task flow So this is an app we built a couple of months ago for a code lab, for an Android testing code lab It’s a simple note taking app, where you have a list of notes You can add a note, add some text, save it That’s pretty much it The thing is, this app is a nice way of looking at tests and explaining them Because UI tests seem like a very human way to test your apps You get the interface You look at it as if you were looking at your phone And what do you do? You first identify some view you want to perform actions on So in this case, I want to add a new note So I click the fab, right? And then, on the second screen, I want to type some text in, save the note, and then, finally, verify if the note was added It’s a simple thing, a very, very human way to test an app And how does it look in code? So Espresso has this simple, really fluent API that lets you express these kinds of tests in an easy way, in code So let’s do a quick run-through So first of all, like I said, we need to find a view And here we are looking for a view with the ID addNote It’s the fab When Espresso finds the view, I want to perform an action on it I want to click on it And then, on the second screen, again, I’m finding views, in this case, the input fields, and I’m performing another action It’s typeText So I’m typing text into them again, clicking on a fab to save the note And here in this final last line of code, you see things are a little bit different I don’t want to do any more actions I want to verify the result of my tests So instead of performing an action, I’m actually doing a check I’m trying to match the note that I added, if the text that I added with the note is actually displayed on the screen So that’s the basic Espresso test And one nice thing about Espresso is, you might notice that, apart from those basic building blocks, these onView calls, these viewMatches and viewActions, and assertions at the end, there’s nothing really in between And that’s the magic of Espresso This is the whole point of using this framework Notice how in the previous test that I displayed, we went through another activity and back We went through three different screens We performed typing We had to wait for the screens to change, and finally to display the final result But there was no code in between to wait for those events That’s Espresso But when people come from different backgrounds, from the different testing frameworks, maybe, and they try to use Espresso for their apps, I see a lot of questions on Stack Overflow, and answers that try to work against that API So let’s look at something that I’ve seen in answers on Stack Overflow that is not entirely correct So instead of working with Espresso, and using the constructs that I’ve just discussed, like viewMatches, people usually ask a question, “how do I get the view?” How do I get that view object to do things to it, to change properties and verify things? Well, you really shouldn’t This is a very obscure API This is not meant for you to use This will just not work The other thing that is a little bit more dangerous is getting the activity and finding stuff in the view hierarchy This line of code would actually work, but it’s not really what you want to do I mean, it will work as in it will not throw an exception, but again, this is working against Espresso And one question for you– this is something I’ve seen How many people think this test will actually pass? No? Well, it will, because it doesn’t do anything

OnView doesn’t run any real Espresso actions It just returns a viewInteraction object, which you can act upon next, and cue actions, or do assertions This doesn’t even look for the view in the hierarchy So coming back at a proper Espresso test Like I said, this just returns a viewInteraction object And only when you actually act on that, this is where the Espresso magic starts And so in this first part of this presentation, I just wanted to talk to you a little bit about internals, so that you have the knowledge that will help you in building your tests, and finding all the different scenarios, and different ways that your tests can fail So let’s look at the viewInteraction class This is source code from Espresso It’s open source You can go look it up You can open it yourselves You can dig into it I really encourage you to do it It’s not that big, and it can give you a better understanding of what happens under the hood So when I perform an action on the viewInteraction object, this method, doPerform, it’s called And the first very important thing that happens is, it starts running everything that it does on the main thread So the test method that you write, it’s actually on a different thread If you want to work with views, work with a view hierarchy, we have to switch to the main thread first Then this is a very, very important thing UI controller is the most important part of Espresso, I would say This is an internal class in Espresso that has this method called loopMainThreadUntilIIdle And this is where all the magic happens that I mentioned before This is the place where Espresso waits for your app to be idle And I will discuss in a second what it actually means for your app to be idle And only then, only after Espresso finds that it can run, it can actually run your actions safely when the app is not doing anything, will it actually kick off traversing the view hierarchy, finding the view, and matching it against your matter Only then And then, when it finds the view, of course, it performs the action and passes it into the UI controller So if you’re writing any custom actions, you can use it again instead of trying to do things without Espresso So UI controller loopMainThreadUntilIdle, a long name, but– So what it does? It first sets up conditions It looks at AsyncTasks in your app It also looks at AsyncTasks from the support library, which use a different thread pool So it needs to look at both of those Then it looks at all the idlingResources, which is a custom mechanism to tell Espresso that your app is not idle, which I will discuss in a second It sets up all these conditions, waiting for all these things to be idle, and then runs another method, which just loops and waits until these conditions are met And what’s important in the end, it also looks at the main looper The main looper is something associated with your thread that has a message queue So it basically looks in the message queue if there are any events that are still pending, still preventing Espresso from running safely And there is one common misconception about this So if I have a handler that’s attached to the main thread, so I’m posting to the main looper If I post a message, post a runnable that’s delayed 500 milliseconds, what do you think? Is the app idle now, after I run this line of code or not? Who thinks the app is idle? It’s not, and you’re right You must be really advanced Espresso experts since you came to this talk So when the queue is empty– so this is again part of Espresso This is part of a class that looks at the message queue, and determines if it’s safe to run So the first condition is pretty straightforward If the queue is empty, if there are no events on the main thread that are waiting to be executed, then, of course, we can run But then there is this other part of the condition And what is this TASK_DUE_LONG? Basically, it’s a task that’s a long time in the future And if you look at another piece of code that looks at the queue state, there’s actually a constant that we came up with when working with Espresso for a long time, and testing different scenarios And basically, we found that if we look only at messages in the message queue that are up to 15 milliseconds in the future, then this will work for many, many scenarios So it’s just one thing to be aware of, because that’s a common misconception I’ve seen online So if I post something really far in the future, Espresso can run And switching back to idlingResource So idlingResource ia a pretty simple but powerful concept

that you can use, if you have long running operations on different threads in your app, on threads that are not using AsyncTask or AsyncTaskCompat, because Espresso can synchronize on those But if you have some kind of network operation, or some kind of long computation, something you have to wait for until your app is actually considered idle, you can just implement this interface And again, it looks pretty simple, but lots of developers, especially in the beginning, and everyone is a beginner at some point, of course, people actually do a lot of computation, or figuring out if the app is idle and in the isIdle method And I really encourage you to make it as simple as possible This would be just returning a Boolean flag if your app is idle or not Don’t call on transitionIdle in the isIdle method Instead, when your app actually becomes idle, when your network request finishes, your computation finishes, then remember to call onTransitionToIdle on the callback that Espresso supplied to you Because that’s really telling Espresso “I’m going to be idle now Check my state, maybe Espresso can run now.” And I just want to mention another powerful method on the UI controller If you’re ever writing any custom interaction and custom actions, whenever you feel like you want to use threadSleep, because you sometimes need to pass between an event that you want to happen, don’t use threadSleep, please Instead, use the construct we give you in Espresso Use this method It sets up a condition It waits until the time passes, and then, again, with loopUntil, you get all the same guarantees about the message queue about the app being idle So please use those things if you’re doing more advanced stuff And moving on, in the second part, I just want to talk to you about tips and various pieces of advice that I gathered from internal teams of Google working with Espresso Hopefully it’ll help make your test better, less flaky, and maintainable So I’m going to go one by one through them I mean, do you care about your code structure, your apps architecture, your good quality overall for your app? Probably, yes Well, then, why shouldn’t you care about the same for your tests? Let me just show a very, very simple example, if you’re still not convinced So with Espresso, sometimes, you need to code pretty close to the implementation so for example, if you use onData to look for views in your adapter views in a list view The simplest example of this– you have a list view, an adapter backed by map items And so you write this line of code Your test passes, and then you need to use it in another test, and another test, and so on So you copy paste it everywhere And then imagine you change the adapter You change the data that’s backing your list view You’re starting to use a cursor, or whatever else And suddenly, you have to go and change it in every test in your code, which is pretty daunting So instead, just try to abstract away any more complicated matters, any more complicated pieces of code Again, this is very simple You can write your own robots, or more sophisticated ways to abstract away working with screens in Espresso But then you just need to change one place, and your test will pass again Then one thing I want to stress throughout this presentation– please use the available APIs and classes that we give you in Espresso Use the available matchers We provide a lot of matcher for pretty much every view that’s in the framework, for most properties that are in the framework And if something is missing, then maybe we omitted it Maybe it should be there, and it would be nice if you find this kind of situation to please file a bug with us But on the other hand, we can’t know everything about the custom views you make So definitely there are moments when you would like to write your own matchers And another instance of that is if you find that you are combining lots and lots of matters for your actions Maybe it’s nice abstract away this complexity, and write a custom matcher, compound matcher that does that I just want to point out that, again, there are classes that will help you with that So for the simplest matchers, you want to just extend the typeSafe matcher that work on the onViews You don’t have to do casting and things like that This is very similar, but if you want to filter out just certain types of views, just subclasses of certain views, use the bounded matcher Again, you will not have to do the filtering You will not have to do casting and matches safely

You will just get the views of the type that you care about Again, reuse we provide countingIdlingResource Use it if you can You don’t need to write your own Many people try, again, like I said, writing custom idling resources They get tangled up in those, where should I call which method? When am I idle? And so on CountingIdlingResouce as a very, very small API It’s basically you call Increment and Decrement So you call Increment before you start a long running operation And you call Decrement when it’s ended And whenever the counter is at 0, so that means no long running operations are running, and Espresso can consider it idle So please use it, if you don’t have a better reason to write your own And on the topic of idlingResources, sometimes, for example, when using counting, when you use one kind of idlingResource resource for everything, you might find that, in your app, there are times when the app is not idle for a long time And Espresso has some sane defaults for timeouts for such situations But if you find that your app is not idle for a really long time, and it’s actually working as intended, then you might have to adjust the idling policies So there’s an API for that If you have something that’s running for a really long time, and you still want that test to run, then, you might have to adjust that Next, pretty much testing basics, but focus on testing behavior, not layout properties And still, a lot of developers are trying to use Espresso to test the pixel perfectness their layouts And while it’s technically possible, it will make your tests really unmaintainable So if you’re trying to assert that a certain view is displayed at position x and y and pixels, and then you work with different screen sizes and so on, and then your designer comes and tells you, move that to the right, you have to redo all your tests So please don’t do that But at the same time, if you really want to check that a certain view is displayed somewhere on the screen relative to another view, we do provide position assertions But they’re relative They’re easier to maintain If you just need to make sure that a button is next to a text field or below it, then you can use the position assertions Write many small tests instead of large ones And to explain this, I like to think about the whole development process As you start with working on single screens and single features of your app, you start writing tests for those single, contained pieces of your app, a single screen, a single feature, then And these things, during development, change a lot So you will go and redo your tests, sometimes, and just make everything work together But then, as your app gets bigger and more mature, it stabilizes as you’re close to release, things are probably not going to change that much You’re going to fix small details, but the overall flow of the app will not change And that’s when you might start getting longer user flow tests But just don’t overdo it Again, the real value is in the small tests that test every screen, every state of your app And on the same page, launch directly into the desired screen state So again, when testing these self-contained screens and states, launch directly into them Don’t do deep navigation before If you want to test an activity that’s not the first activity in our app, and you need to traverse five different screens to get there something can just break along the way And then you’re not really testing the thing you want to test You’re getting errors about something totally different, totally another part of your code So don’t do deep navigation There’s ways you can easily achieve that So if you just override the activity test rule, you can override the getActivityIntent method Just provide a custom intent If you have an activity that gets some kind of data, and then displays a different state, you can just provide that data in the intent And just remember, if you use this, every test in your class will have the activity started this way If you need some more custom fine grained control, just use the free argument constructor And if you parse false as the last argument, the activity will not be launched automatically for your tests And then, in every test, you can just prepare the intent that you want And just remember you have to launch the activity manually Most UI tests should be as hermetic as possible

So again, you want to test your app You want to test the screen of your app You don’t want to test the network conditions You don’t want to test if the server is working You’re testing the features that you’re coding inside your app, and in your UI So make your test as hermetic as possible There’s tools that can help you with that There’s Espresso Intent There’s Mockito for mocking Remember about dependency injection, and Dagger 2 And basically just make sure you’re isolated from all the layers that you don’t care about Because that’s not really UI testing then, is it? And speaking of Espresso intents, I don’t know if you’ve used it before It’s a really nice thing that we’ve added to Espresso It’s a very small API Basically, it lets you verify intents that are sent from your app, or stub the responses to intents that you send to other applications So here, in the screen, you can see And before I’m setting up response stubbing for an intent that I sent out to the camera app And below at the bottom, I’m just very verifying that when I click the button, my app sends out the intent I encourage you to use it to isolate your test from external applications Learn how to handle long running animations That’s been a common problem in Espresso We try to synchronize on a lot of things, like I said, on AsyncTasks and so on But sometimes, Espresso just simply can’t run because something is keeps animating in your UI And there’s two types of animations I want to call out, specifically So on the left, you can see– oh, it’s not animating That’s curious Oh, it’s animating now Let’s say you have some kind of drawable It’s your own It’s your own animation You created it You control it It’s all up to you, if it runs or not And on the other hand, you have animations that are embedded in the framework So for example, a progress bar is something you don’t really control It’s just a system widget It animates, and there’s not much you can do about it And there’s a way to actually deal with the animations that you control So for running Espresso, anyway, we tell you to disable animations in the system So system wide, we disable the layout animations, transitions, and so on And you can actually leverage that setting, and read it in your applications code, and decide if the animations are disabled, maybe I should also disable my own animations Because, really, that’s what the user said when they adjusted the setting So it’s the right thing to do, anyway And on the other hand, like I said, some things, like the progress bar, are not very easy to work with So you have you will just have to find other ways, like maybe having a separate flavor for your test when the drawable for that progress bar is just not animated There are some tools that can help So for example, in developer tools, you can switch a setting called Show Surface Updates This might help you identify some of those animations that you were not aware of, but are somewhere in your UI, and keep posting events that keep Espresso from running And next, how to handle test failures So your test will fail sometimes And it’s obviously not intended, but maybe the test is wrong Maybe you need to write in some other way So the good thing is, Espresso aims to tell you exactly what went wrong in the test, and how to fix it So we have really descriptive error messages We provide a message that tells you what went wrong And moreover, we provide a dump of the view hierarchy, so you can look at the exact views and their properties, and maybe find the culprit But if that’s not enough, it’s very easy to implement your own failure handler You can attach your own handler, and just log out more data If you have some information that you think would be useful, you can just add it to the log One very interesting use of that that I’ve seen online is someone said that Espresso was actually giving him too much data about the view hierarchy for a very, very complex screen And so he created a failure handler that actually made the logs smaller, to only concentrate on the parts that they care about It’s an interesting use And then there’s more developer tools that can help you with debugging So you can enable showing touches, pointer location, layer bounds Those basically let you inspect better what’s happening on the screen when Espresso runs And also use the Hierarchy Viewer if you just want to interactively explore the hierarchy, for example, find out the IDs of views

or their relative positions in the view hierarchy There’s one more setting, not in Developer Tools, but in Accessibility So on some devices, they’re really slow, or some emulators, especially the older ones Single taps are not registered correctly I mean single taps coming from Espresso I don’t want to go into details, but we really try to hide away the complexity of actually simulating a tap in Espresso But every tap is actually two actions– down and up And if a device is really slow, if it’s bogged down by some kind of background operations, or the system is just not keeping up, these two operations can happen too far apart And then the system thinks it’s a long press So basically, if you change the delay to long, that might help the situation And finally, enable testing for Accessibility issues So that’s something many developers still don’t think about, sadly But really, you want to make sure that your applications are accessible to all people who want to use them And Espresso gives you a very easy way Just enable the Accessibility Validator It’s a very easy way to start testing for very common Accessibility issues So please enable that, and fix your apps, fix your views to make sure the app can be used by anyone And what’s next? I really encourage you to look at the Espresso documentation There’s a section called Advanced Espresso, or Advanced Sample, something like that And you will see lots and lots of more tips and tricks on how to use Espresso, how to use the more unknown APIs of Espresso Do check out the Android Testing codelab It’s not only about Espresso It’s also about how to structure your app to be more testable It gives a great overview of all the testing offerings that we have Finally, we have greatest testing samples We have a testing blueprint And like I said before, remember that Espresso is open source So if you find anyplace where it’s not working the best it could, if we’re missing some kind of matchers, if there’s a source of flakiness for your test that we were not aware of, file bugs, or better yet, file pull requests, and help us to make it even better [MUSIC PLAYING]