[MUSIC] We're going to take a look at how we can go about testing the user interface of our application. because a lot of the things that we're going to care about are how the user goes about clicking on buttons, and what happens, and how our application reacts to these types of changes and events. So, we're going to show you how to use the Espresso framework from Android. And this is a way of testing the user interface of your application and feeding it fake events. So, we don't want to go and necessarily click all of these buttons each time, manually. So, for example, in this login application you can see there's a bunch of buttons and edit text. There's a login button, there's where we type our password in. There's an email that we have to enter in, there's an error message for you to display an error to the user. There's all these things. And you can imagine, if every time you made a code change and you wanted to check if it worked, you had to go and enter your password in again, enter your email again, click the log in button manually, while waiting for this all to load on your emulator, or on your phone that you have plugged in. Then check if the message is correct. All of these things take time, and we want to try to automate this repetition. So let's imagine that we have this log in screen, and we want to check that when the log In button is clicked, which is right here, we're adding a non-click to the login button. We want to check that the password is at least a certain length. So, we'll go ahead and get the password from the password edit text. And we'll say, if the password linked is less than four is going to be our rule. So you have to have at least four characters in your password. So if you've got a password of linked less than four, then we want something to happen. So, what we're going to do is we're going to take this error message view. And we're going to set its text. And we'll say, invalid password. Actually, we'll just say, bad password. Make this a little shorter. Now a better way to do this would be to extract this into a string that was in a separate file for internationalization purposes. But for this we're just going to, for simplicity's sake, we're just going to enter it in directly here. So we would set our error message that we want it to have. And then we might also go and set the visibility to visible. So the way this is going to work is in our, the definition of this user interface, our error message view is initially invisible. And so what we want to do is if they type in a bad password we want to set the text to bad password. So we're going to tell them that they've got a bad password and we're going to display this error message. So, this is some simple functionality that we want to go and test. Now we could go and test this by launching our application, entering in a bad password, clicking on the log in button and checking that this error message showed up. But what we're going to do instead, is we're going to create a test to automate this for us. So we're going to create a test. We're going to say test, no, password link, rule, triggers, your message. You could rename these different things to what you want. I'm just throwing in something here quickly, as an example. So the first thing we need to do is let's first check that when we initially show our application, that this error message is not visible, but that the other things are visible. So let's go ahead and add a different test for that. We'll say public testThatErrorMsgIsNotInitiallyDisplayed(). So we're going to now first initially, we're going to test that the error message does not show up, so width view, or on view. So first we need to say on view, which is telling Espresso what we're trying to test. So we're going to say on view with ID, ID.errormessage. So we're saying, go and check the view with ID error message. And then we're going to tell it what to check. Check matches not as displayed. And what this line says is, and I'm going to go ahead and break this down for you piece by piece. So the initial part is we need to tell Espresso, which part of our user interface we're trying to check something on. So in that case we have a view that we want you to go and check something in. So once we've told it that we're looking for a particular view, we have to tell it how to find that view. And in this case, we're telling it we know the exact ID of the view that we care about. So we're saying go and find the view with ID R.id.errorMessage. So we're telling Espresso the specific view that we care about that we want to check. And then the .check part is we're telling Espresso here's what I want to make sure is true about the state of my user interface, or of the state of that particular view. So I want to check that the view of ID R.id.errorMessage, I want to check that it matches a particular search. And then this matches means that it's a assertion about the state of that view. So what I'm checking for is that it matches the state, not is displayed. So what this is telling Espresso is, I'm expecting the view R.id.errorMessage to not be displayed. And so, that will then create a simple test for us. Now, I'm going to go ahead and work a little bit more on some other tests. We'll run this in a second. So the next thing I might want to say is so initially I'm expecting the error message not to be displayed. So the next thing I'm at when I check, is if I enter a invalid password, that this error message is displayed. Well how am I going to actually enter an invalid password? Well what that means is, I've got to go and find the password edit text here. So I'm creating a new some Espresso code here to say, on this particular view that has the password edit text, I'm going to want you to perform an action on that view. So I'm trying to get that view into a state and perform. You can think of this as, you want to take a view and you want to perform some action on it, just like a user would. So you might want to click a button, or you might want to enter some text. So, what we're going to say is, perform(typeText and we'll do (''abc'') so that should fail our password rule. That should be less than four characters long. So, what we're doing is we're taking the password entry field, and we're getting it into a particular state by performing an action on it. So the next thing we'll want to do is we'll then, once we've actually Enter the text, is we need to go and click the LoginButton. So we'll take the LoginButton, and again what we want to do is do something that the user would do. So that's going to be a perform, and we're going to say, click. So we've taken the password edit text and we've typed text into it, just like the user would. Now we're taking the login button and we are clicking it just like a user would. So what we've done is we've actually replicated what we would have to do manually otherwise. You can imagine if you had to do this over and over on your own manually. Do these two simple actions, it'd end up taking a lot of time and a lot of effort. So we're automating all of that. Our tests don't do a whole lot yet, but let's just go ahead and run them to show you that we can do this. So we're going to go ahead and run our LoginActivityTest. And this is a great keyboard shortcut to know, is how to go and launch some of these unit tests or rerun your test suites through the keyboard commands. That's really helpful to have those keyboard shortcuts on hand, but I'm going to do these things from a GUI perspective so that you can see what I'm doing as I do it. So we can rerun these tests and hopefully we should see that our basic assertions about the error message not being displayed initially. And then also the ability to go and perform actions, although we don't actually check anything in those tests, can actually be done. So we'll wait a minute for this to run and then we'll come back and see that it did. So we can see that our tests were run and they both passed. So we know initially that our error message is not displayed. And then we also see that we can actually go and imitate what a user would do, we can mimic the typing of text and clicking on different views. Let's go ahead and build out our second test and check that our assertions about, or our expectations about, what's going to happen are really true. So what we're expecting is that after they've typed in a password and clicked on the log in button. That if the password is less than four characters, that we're going to set the error message to bad password. And we're going to make the error message visible. Now, a nice way of doing tests normally is to go and assert something that we know not to be true or that we would expect to fail initially when it got checked. For the sake of making these videos take a little bit less time to get through, we're just going to go ahead and directly build out what we expect. So we know that we've typed in text that is less than four characters and we've performed a click on the log in button. So now what we should expect is first we're going to expect that the view, which is the R.id.errorMessage view. We're going to expect that now it should be displayed. So we're going and we're doing basically the opposite of what we did initially. So up here we checked not is displayed. Now we're just going and we're checking that it's actually displayed. So that's the first thing we're going to do. We can also, well actually just go ahead and keep it going over here. We'll check that the error message is what we expect it to be. So we're going to expect that we have bad password as the text. So now what we've got is we've got a more extensive test. We've got the initial editing of the password. We've got performing the click on the log in button. And now we're actually going to go and check that our error message, whereas it wasn't displayed before because we've entered text that's too short. That our error message ends up getting displayed. And that the text in that is bad password. If we go and then run this, we should see that all of this test pass. So our tests have finished running and we can see that our new test passes. We could also go and check that this thing doesn't pass, we could change the password, do something else, and see that it doesn't pass. But this is very helpful to us. Now, if we wanted to go and test, for example, let's say that if we enter a valid password, we would expect something else to happen. We could certainly do that, but let's just go ahead and without adding any more code, just based on our current state. Let's go add a new test. Test valid password does not display error message. So we're going to expect that if we go and do what we did up here where we go and enter some text and then click on the log in button. And we'll just say a long valid password and we'll add some semi-random stuff to it. That when we click on that, we're expecting that that will not trigger the error message being displayed. So we're going to go back and we'll say And. Error message, check. Matches not is displayed. So now we're adding a new rule, our expectation is that if we enter a valid password in, that we're not going to end up showing the error message again. So we'll go ahead and run this like we did before. So we can see that all three of our tests now are passing. We're ensuring that the error message is not initially displayed, that the valid passwords do not display the error message. And that if we trigger this password link rule, that it makes the error message show up on the screen. So we're automating, essentially, what we would have to manually go in and test otherwise, without Espresso. So let's take a little bit of time, I want to go and dive in a little bit more in detail of these tests and how we build them and how we specify the views. Just to give you a little bit more intuition about how this works, you can set it up on your own. The first thing that I wanted to make sure of is that you've imported the correct libraries into your project. So to do this, if you open up your build.gradle file, you want to make sure that you're using Espresso and that that is present. So I'm importing a particular version of Espresso, depending on when you watch this video you may need to import a newer version of Espresso. But you want to make sure that Espresso is present and this also shows you typically the testing dependencies you're going to want to use in your application. Now in this case it's important to note that we're adding Espresso only at test compile time, Android test compile time. And that's because we don't want to compile Espresso into our application. We just want it present at the time that we are running these tests on our application. So you want to make sure you do that. When you make these changes, more than likely you'll be prompted to synchronize your project. And you'll want to make sure and go ahead and do that. We go back to the test. You'll see that we're still running with the Android JUnit 4 class as the run with and you'll see that I've used a lot of these on view with ID the click is displayed, all these different short hand methods that we have present in our test or actually things that are statically imported from within espresso or hand press. So when you go, if you go and start creating a test and you can't find these things and you're not getting autocompletion out of Android Studio helping you find them and import it, here's where they are. You can go and import these things from the espresso framework. So I'm importing everything in Espresso view matchers, view assertions and view actions and then also in hand cress matchers. And by doing this static import, you'll notice that I'm not just importing it, but I'm importing it statically and what that means is go and find every all the methods within here these static methods and import them into. The current class and that's what allows me to say, onView, which is actually defined in one of those things that I've statically imported. So, that's the first thing. If you start trying to create these things and you can't find these methods, you'll want to make sure you have those static imports. The second thing you want to know is you're going to have essentially two parts to all of these statements that you're making. The first part is where you tell Espresso what it is? What is the subject of the thing that you're trying to assert or perform an action on? So, are you either checking the state of something or you're performing an action on something to get it in a particular state. So, you'll have a subject of that action or you have a subject of that check of its state. And the way that you specify the subject is you always an onView which is telling that the view that you're trying to check or interact with and then you have different ways of telling it how to go, and find the particular view you want to work with. In this case, all of our examples we're doing with ID. Meaning, we're going and getting a particular ID, but you can also go and do things like check multiple views or you can go and check for views that have a particular state. So we might want to say, for example, has a particular set of text in it. So for example, we could say with text abc. So for example, we knew there was some view that had that text in it and we wanted to go and find it. We could say with a particular text or we could go and make an assertion about all views that are displayed even and then go, and check that something is true about those views. Maybe we want every view that's displayed at a particular point in time to have the text abc. Now this is a lot of text obviously, but you can go and build up very complex sort of matches against the views and then check different states. So depending on what you need to do, most of the time, probably you're going to want to go and look at a very specific view with ID and then check some state of it. Now, the second part of all these rules or statements that we're making is the check. Here's what we want to is sure is true about the subject that we're looking at. So on the view with error message, we're always going to typically have a check and then we can specify what it is that is our expectation. We're expecting that the view matches the state not is displayed and you can go, and put on all kinds of different checks in here related to what text is in there. For example, we could have gone and said, why we're expecting not to have a particular text. So we're expecting it not to have the word few in it or we're expecting initially, for example, this was the password, we're expecting it not to have detects bad password in it or maybe we want to initially assert that the error message is blank. So, we are expecting no error message to be in there. So, you can go and specify what these different checks are. Now there are a whole bunch of different options that are available and I'm not going to go through all of them, but I encourage you to take a look if you begin doing some of the autocompletion examples from Android Studio and you type with or is. You could begin seeing all of the different options that are available to you. For example, this chat or is focusable or is enabled is selected. You can go through and look through all of these things are available, and figure out what all is there. If you go to Google online, you can also find all the different options. Now there's more than we could possibly talk about. But as a developer of sustainable applications, you'll want to have an understanding of how you go and specify all these conditions. I'm just going to put this back the way that it was. So, we initially wanted it not displayed. Now we'll always have on view typically and then we'll be checking stake, but sometimes we need to get the view into a particular state. And so in those cases, we will take a particular subject and then we will perform a series of action on it. So the way to think about this is if you need to get the UI into a particular state by performing actions that you would normally manually perform as a tester, then you will go and use perform. And then once you've gotten it in the state that you expect it to be in, you would go and check your expectations. So in this case, when you go and perform, you can go and do all kinds of things like a user would be. So whenever you go into perform, then you'll have all the different options of the actions that you can take. So clicking on something, typing text into something. These are the inputs to the perform. So, you're specifying exactly what is going to take place. Now using these simple sort of primitives, you can build up very complex automated tests that if we go and change something can allow us to very quickly check and determine if we've made any mistakes or broken anything and our original application. So you can imagine once I've built up a bunch of these tests, if I went and forgot, for example, to display the error message and I reran my tests, then I'm going to catch that error, because I'm looking for and inserting that after I go and perform this clicks that the error message is going to end up being displayed down here. If I went, for example, change the error message and it doesn't match my expectations, I can see that. And so, this allows you to build up that confidence that you need in your code to be able to quickly evolve it over time and make it sustainable. So if every time you go and make a change, you have to go an manually run through all the equivalent of everything that I've done here. You can imagine that's going to take a lot of time and you may start skipping some of these tests, because you say, well, I know that works or you assume that it works. But in reality, you don't. So this automation is critical for making sure that as you change your code, you're not breaking things. And that as you change your code, you have the confidence to know that you can make a change without breaking things that you aren't realizing. So it's about building confidence in your code, making it, so that you can edit and change this quicker. But it's also about another developer comes along being able to see, well, this is their expectation about how this operates. So if I go and change something, I know what their expectation is and I have confidence that I'm not going to change something that was different and create an expectation that's different from what the original developer did. So it's about not only passing on knowledge, it's building confidence in our application and the code base and building confidence in our ability to make changes without breaking things.