This article differentiates unit tests, such as those written for jUnit, from UI tests in Espresso through both purpose and technical value.
What is Espresso?
Espresso is an automated UI testing framework for Android apps. They are scripts written in Java that simulate interactions with the app while it is running, either in an emulated environment or on a physical device.
Espresso tests are “instrumented”, which means that internal workings (context) about the app such as object names, runtime variables, and other symbolic information is made available to the tests. Using Android Debug Bridge (ADB) to provide runtime feedback between tools like Android Studio and the app as test activities are executed on the target device.
How is Espresso different than Unit Testing?
Unit tests focus on small portions of code (i.e. class-level methods) and provide basic validation that code is working as expected. Espresso tests provide basic validation that the UI is working as expected.
Early feedback from lots of tiny unit tests on each build help developers know when they just “broke” something by changing some other portion of code. Early means often, and often means that speed and reliability of these tests are crucial.
To that end, unit tests typically are hermetic and rely on stubs/mocks to stand in for dependencies. Antithetically, Espresso UI tests work through platform API which requires a runtime and device capabilities that are not faked. This provides more realistic feedback on code that might work at the unit level, but fails when chained together or during basic usability validations.
When should we write Unit Tests?
Always. You can figure out for yourself what total percent of lines of code are covered by unit tests, but this is a battle against low-level technical debt. How often do you want to be surprised when a change that seemingly had nothing to do with one piece of code breaks because expectations over what that code does weren’t spelled out in a way that could be exercised regularly?
That’s really what validation testing boils down to: are we communicating basic expectations about the things we’re about to ship? Unit is just at a very low level, but the same applies at the UI workflow level too.
When should we write UI tests?
Whenever you have a UI…that’s pretty obvious, right? People use an app, they don’t call your class methods in isolation with static data on emulators. Eventually you have to get real: simulate clicks, drags, gestures, network conditions, and platform upgrades because that’s how real people are using your user interface (a.k.a. your app).
How much UI testing you do is up to you, but it boils down to time cost. UI tests are often more complicated to write, though as we see with Espresso, a developer-focused syntax and fast execution speed goes a long way to reducing cultural friction to writing UI tests as part of “development complete”.
Sideline: API teams, you don’t get off so easily either. Your developer experience is your UI, the patterns by which your users call your endpoints, designed or otherwise, are equivalent to workflows. Equivalent to UI testing for app developers, holistic API tests that simulate known trends and expectations on your API will help you isolate breaking changes earlier and faster in your build cycles, it’s that simple.