Skip to content

Commit 91ef330

Browse files
authored
Merge pull request #3 from matt-oakes/espresso
Add tutorial for Espresso UI tests
2 parents c5e307e + 42f5006 commit 91ef330

File tree

9 files changed

+289
-2
lines changed

9 files changed

+289
-2
lines changed

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ DEPENDENCIES
4949
tzinfo-data
5050

5151
RUBY VERSION
52-
ruby 2.2.2p95
52+
ruby 2.3.1p112
5353

5454
BUNDLED WITH
5555
1.14.6

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This is a [GitHub Pages](https://pages.github.com/) repo, so you can render the
66

77
1. `bundle install`, which will install Jekyll.
88
2. `bundle exec jekyll serve --watch`
9-
3. go to <http://localhost:4000>
9+
3. go to <http://localhost:4000/android-tutorials/>
1010

1111
You are now ready to make changes!
1212

assets/main.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,22 @@ pre {
2929
background-color: #282c34;
3030
padding: 15px;
3131
}
32+
33+
.aside {
34+
position: relative;
35+
padding: 16px;
36+
margin: 0 32px;
37+
}
38+
.idea {
39+
background-color: #FFF9C4;
40+
}
41+
.aside p.aside-title {
42+
font-weight: bold;
43+
margin-bottom: 0;
44+
}
45+
.aside p {
46+
font-size: 0.8em;
47+
}
48+
.aside p:last-child {
49+
margin-bottom: 0;
50+
}

index.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,21 @@ This is the home for the codebar android tutorials! These are designed to be use
3939
</div>
4040
</div>
4141

42+
<div class="col-lg-4 col-md-6 col-12 text-center" style="padding:5px;">
43+
<div class="card">
44+
<h2 class="emoji-title text-center">
45+
<i class="material-icons">personal_video</i>
46+
<i class="material-icons">touch_app</i>
47+
<i class="material-icons">phone_android</i>
48+
</h2>
49+
<div class="card-block">
50+
<h4 class="card-title">Espresso UI Testing</h4>
51+
<p>Automatically test your cookie clicker app using Espresso</p>
52+
<a href="{{ site.baseurl }}/worksheets/espresso-testing/" class="btn btn-primary">Read Tutorial</a>
53+
</div>
54+
</div>
55+
</div>
56+
4257
<div class="col-lg-4 col-md-6 col-12 text-center" style="padding:5px;">
4358
<div class="card">
4459
<h2 class="emoji-title text-center">
491 KB
Binary file not shown.
198 KB
Loading
325 KB
Loading
183 KB
Loading
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
---
2+
layout: page
3+
title: Espresso UI Testing
4+
---
5+
6+
## Introduction
7+
This tutorial follows on from the [first one where you built a cookie clicker]({{ site.baseurl }}/worksheets/1-introduction/). If you worked on that tutorial already, follow along using the code you wrote previously.
8+
9+
If you didn't work on that tutorial, or you don't have the code anymore, you can download a completed project to follow along with [here](downloads/cookie-clicker.zip). Download the file, unzip it and then open it with Android Studio using the *Open an existing Android Studio project* button on the welcome screen.
10+
11+
## What is UI testing?
12+
To make sure your software works properly you need to test it whenever you make a change that you want to release to your users. To do this manually for even a small app this is a boring, repetitive, and time-consuming job. That's precisely the sort of thing which we use computers for! Automated tests are pieces of code which test that your software is working correctly. You can set them up to run regularly and on many devices so you don't have to manually test your app every time you make a change. Plus they're usually simple and fun to create!
13+
14+
We are going to write some UI tests for our cookie clicker app. A UI test is also known as a "functional test" as it is testing the functionality of the app. There are other types of tests such as "unit tests" which you may have come across in the Javascript, Ruby, or Python tutorials.
15+
16+
A UI test will take a set of instructions about what to click on and checks that the application responds correctly. For example, on a sign in screen you might have an espresso test to check that an error appears if you enter an email address with the wrong format. UI tests are doing the same thing as if you were clicking on and testing the app manually, but they can do it much quicker, and they don't get bored when they have to do it for the 100th time!
17+
18+
First, we need to set up our testing framework.
19+
20+
## Setting up Espresso
21+
We are going to be using a testing framework called [Espresso](https://google.github.io/android-testing-support-library/docs/espresso/index.html) to interact with our app and test that it is working correctly. This is a tool provided by Google themselves.
22+
23+
First, we need to make sure the libraries are installed correctly.
24+
25+
In Android Studio, expand the `Gradle Scripts` section at the bottom of the project explorer on the left. Then double click to open the `bundle.gradle (Module: app)` file. Make sure it's the `Module: app` one and not the `Project: CookieClicker` one. This is the file which describes how to build and run our Android application. We need to make sure everything is set up correctly here to let us use Espresso.
26+
27+
Inside the `dependencies` section, make sure that these two blocks of code are there:
28+
29+
```groovy
30+
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
31+
exclude group: 'com.android.support', module: 'support-annotations'
32+
})
33+
```
34+
35+
And:
36+
37+
```groovy
38+
testCompile 'junit:junit:4.12'
39+
```
40+
41+
They might already be there depending on how you created your project. If they aren't, add them in. These lines tell the Android build system which version of the Espresso library to use.
42+
43+
Also, make sure that this line in your `android.defaultConfig` section:
44+
45+
```groovy
46+
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
47+
```
48+
49+
The complete file should look something like this (_Don't copy this as some of your settings will need to be left as they were before. Also, don't worry if yours has some extra bits. Ask your coach if you aren't sure if you have done it correctly_):
50+
51+
```groovy
52+
apply plugin: 'com.android.application'
53+
54+
android {
55+
compileSdkVersion 25
56+
buildToolsVersion "25.0.2"
57+
defaultConfig {
58+
applicationId "io.codebar.cookieclicker"
59+
minSdkVersion 14
60+
targetSdkVersion 25
61+
versionCode 1
62+
versionName "1.0"
63+
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
64+
}
65+
}
66+
67+
dependencies {
68+
compile fileTree(dir: 'libs', include: ['*.jar'])
69+
compile 'com.android.support:appcompat-v7:25.3.1'
70+
compile 'com.android.support.constraint:constraint-layout:1.0.2'
71+
72+
testCompile 'junit:junit:4.12'
73+
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
74+
exclude group: 'com.android.support', module: 'support-annotations'
75+
})
76+
}
77+
```
78+
79+
Press the *Sync Now* button in the golden yellow bar which has appeared along the top of the code editor window. If the bar disappears after syncing, then everything is set up correctly! If the bar shows and error message and a *Try Again* button then something has gone wrong. Take a look at the error at the bottom of the screen to see if you can fix it, or ask your coach for help.
80+
81+
## Writing our first test
82+
Now we have everything set up; we can write our first test!
83+
84+
In the project navigator on the left panel of Android Studio, navigate through `app -> java -> <package name> (androidTest)` where `<package name>` is the name you used when you set up the project. Right click on the `(androidTest)` line and choose `New -> Java Class`. In the window which pops up, give it a name of `CookieClickerTest` and then press `OK`. This will create and open a file which looks like this:
85+
86+
```java
87+
package io.codebar.cookieclicker;
88+
89+
public class CookieClickerTest {
90+
}
91+
```
92+
93+
Above the `public class` line, add in this line:
94+
95+
```java
96+
@RunWith(AndroidJUnit4.class)
97+
```
98+
99+
Remember to use the autocomplete as much as possible as it will also add in some `import` lines above for you. This line tells Android how to run the tests we are about to write.
100+
101+
Inside the `class` add the following line:
102+
103+
```java
104+
@Rule
105+
public ActivityTestRule<MainActivity> activityTestRule = new ActivityTestRule<>(MainActivity.class);
106+
```
107+
108+
This is a "test rule" and test Espresso which activity (part of our app) we want to test. We have chosen the `MainActivity`. This rule will make Espresso open this activity before running our test so we can see the cookie clicker and test it is working.
109+
110+
We now need to actually write some test code. Inside the `class`, create a new method called `totalStartsAtZero`. It should look like this:
111+
112+
```java
113+
@Test
114+
public void totalStartsAtZero() throws Exception {
115+
116+
}
117+
```
118+
119+
We will be writing one of these methods for each test that we want to perform. As you can guess from the name, we are first going to check that the counter starts off at zero.
120+
121+
Inside the method, write the following code:
122+
123+
```java
124+
onView(withId(R.id.lblTotal))
125+
.check(matches(withText("0")));
126+
```
127+
128+
So what are we doing here? The first line (`onView`) is finding the view which matches the requirements we have given to it. We have asked for the view with the id of `lblTotal` using `withId(R.id.lblTotal)`. Remember that this is the id we gave to our `TextView` in the first tutorial in the `activity_main.xml` layout file. The second line is checking that the view matches some conditions. We are checking that the view has the text `"0"` using `withText("0")`.
129+
130+
This pattern of getting the view with a set of requirements and then checking something with it forms the basis of how Expresso tests work.
131+
132+
The completed test file should now look like this (_remember, don't copy this directly as some of your code (such as the package name) need to be different. As your coach if you are not sure_):
133+
134+
```java
135+
package io.codebar.cookieclicker;
136+
137+
import android.support.test.rule.ActivityTestRule;
138+
import android.support.test.runner.AndroidJUnit4;
139+
140+
import org.junit.Rule;
141+
import org.junit.Test;
142+
import org.junit.runner.RunWith;
143+
144+
import static android.support.test.espresso.Espresso.onView;
145+
import static android.support.test.espresso.assertion.ViewAssertions.matches;
146+
import static android.support.test.espresso.matcher.ViewMatchers.withId;
147+
import static android.support.test.espresso.matcher.ViewMatchers.withText;
148+
149+
@RunWith(AndroidJUnit4.class)
150+
public class CookieClickerTest {
151+
@Rule
152+
public ActivityTestRule<MainActivity> activityTestRule = new ActivityTestRule<>(MainActivity.class);
153+
154+
@Test
155+
public void totalStartsAtZero() throws Exception {
156+
onView(withId(R.id.lblTotal))
157+
.check(matches(withText("0")));
158+
}
159+
}
160+
161+
```
162+
163+
Let run our test to make sure the app is working correctly. Press the "play" button to the left of the method and pick your Android device or emulator to run the tests on. This might take a short amount of time but the app should appear and the quickly disappear, and Android Studio should show a "Tests passed" message. This might even be too quick to see, and that's the advantage of using automated tests! Run it a few time if you want to test it is working all the time.
164+
165+
![Test passing](images/test_passing.png)
166+
167+
Just to see what happens when a test fails, change the check to look for `"1"` and run the test again. You should see an error message saying what happened and some hints on how to fix it. There's a lot of information there, but there's normally enough to know what went wrong.
168+
169+
![Test failing](images/test_failing.png)
170+
171+
Change you test back to check for `"0"` so that it passes again.
172+
173+
## Tapping on the cookie
174+
We should now do something a little more interesting with our tests. We are going to test that pressing on the cookie increases our total counter.
175+
176+
Create a new method called `totalIncreasesWhenCookieClicked`. Inside this method add the following code:
177+
178+
```java
179+
onView(withId(R.id.imgCookie))
180+
.perform(click());
181+
```
182+
183+
This looks similar to the code before, except this time we are performing an action rather than checking something. The first line finds the view with the id `imgCookie` (take a look at your `activity-main.xml` file if you can't remember which view this was). The second line then performs a click action on it. This will call our `OnClickListener` in our `MainActivity.java` file and should update the total label. We now need to write a check for that.
184+
185+
To do this, add in these lines to the new test method:
186+
187+
```java
188+
onView(withId(R.id.lblTotal))
189+
.check(matches(withText("1")));
190+
```
191+
192+
This is almost exactly the same as the code we wrote for our `totalStartsAtZero` test, but we're instead checking to see that it is now `"1"`.
193+
194+
Our completed test should now look like this:
195+
196+
```java
197+
@Test
198+
public void totalIncreasesWhenCookieClicked() throws Exception {
199+
onView(withId(R.id.imgCookie))
200+
.perform(click());
201+
202+
onView(withId(R.id.lblTotal))
203+
.check(matches(withText("1")));
204+
}
205+
```
206+
207+
Let's run this new test using the play icon next to the `totalIncreasesWhenCookieClicked` method line. This test should take just long enough for you to see the 1 on the screen, but it's still so fast that you might blink and miss it!
208+
209+
<div class="aside idea">
210+
<p class="aside-title">Aside: Breakpoints</p>
211+
212+
<p>If the test is running too fast and you would like to see what is happening clearly, you can try using a _breakpoint_. A breakpoint is a marker which tells the application to pause at a particular line of code so you can see what it is doing. They are very useful for debugging your apps!</p>
213+
214+
<p>To set a breakpoint, click in the margin to the left of the line of code you would like the test to stop on. The first line of the <code>totalIncreasesWhenCookieClicked</code> method is a good place. Then, use the "debug run" button (the one with the bug and play icon to the right of the "play" button you used before).</p>
215+
216+
<p>Now when the test runs, it should stop on that line and show the "debugger" panel at the bottom of the Android Studio window. You can use the buttons in that panel to "step" between lines or to continue running. Hover over the buttons to see a tooltip for what they do and ask your coach if you are unsure.</p>
217+
</div>
218+
219+
## Getting a high score!
220+
We've now tested all the functionality of our app, so now let's do something just for fun: let's make Espresso click loads of time on the cookie and get a high score!
221+
222+
Create a new method called `achieveHighScore`. Copy the code the click test you just wrote and wrap the code to click the cookie image in a for loop from 0 to 100. You then need to check that the total counter has reached `"100"` after the for loop has completed. Ask your coach, if you're not sure how to do this, or take a peek at the code below:
223+
224+
```java
225+
@Test
226+
public void achieveHighScore() throws Exception {
227+
for (int i = 0; i < 100; i++) {
228+
onView(withId(R.id.imgCookie))
229+
.perform(click());
230+
}
231+
232+
onView(withId(R.id.lblTotal))
233+
.check(matches(withText("100")));
234+
}
235+
```
236+
237+
If you run this test it should take long enough that you can see what's going on.
238+
239+
As well as running the tests one by one, you can run all your apps tests by pressing on the "double play" icon next to the `public class CookieClickerTest` line. This will run all the tests in this file one by one and let you know which ones pass and fail.
240+
241+
![All tests passing](images/all_tests_passing.png)
242+
243+
## Further information
244+
You have now tested your cookie clicker app!
245+
246+
You can read more about Android testing using the links below:
247+
248+
* [Espresso documentation](https://google.github.io/android-testing-support-library/docs/espresso/index.html).
249+
* [Android testing documentation](https://developer.android.com/studio/test/index.html).
250+
* [Using the Espresso test recorder](https://developer.android.com/studio/test/espresso-test-recorder.html).
251+
252+
## Possible extension
253+
You can try extending your cookie clicker and tests by adding an [`EditText`](https://developer.android.com/reference/android/widget/EditText.html) for you name and a button to submit a high score. Make sure you write some tests for it too!

0 commit comments

Comments
 (0)