I use this repository as storage of Android UI testing practices from my experience: test patterns, naming conventions, wrapper methods for test and device actions, etc. Or as a part of my programming portfolio.
Some of these come from single projects, others — from common test codebases. They are written both in Java and Kotlin.
🌵 It's not a separate framework, it's just helpers and aliases for personal reuse in the future.
In this repository, there are a simple Android app and Instrumentation tests.
The app has only 3 screens:
There is a test class for each screen. Tests are written based on concepts and tools which are described below.
All testing stuff is made with the help of the following frameworks:
- Espresso — Instrumentation testing framework by Google
- Barista — built on top of Espresso and provides more simple API
- UI Automator — allows you to interact with system apps and dialogs
- AssertJ — provides a rich set of assertions
Everything in this repository was done before the release of a very promising Kaspresso framework. Some of the wrappers presented here (e.g. waiters) could now be well-replaced by their Kaspresso implementation.
UI tests are written with the Testing Robots design pattern, which is very similar to Page Object.
The idea is that each app screen should have its own Robot where you describe test steps which you can apply to the screen. You then chain these steps in a test.
See the examples:
- Java:
ScreenRobot
,ScreenTest
- Kotlin:
ScreenRobot
,ScreenTest
You can figure out the base concepts of the pattern from this talk by Jake Wharton.
Proper naming is very important:
- When you see a test name, you should understand exactly what it verifies, under what conditions, and what is the expected result
- When you see a test step name, you should understand exactly what is being done in the app during this step execution without a need to read the step's source code
For test names here I used an old but relevant convention by Roy Osherove:
@Test
public void unitOfWork_stateUnderTest_expectedBehavior() {}
unitOfWork
— main object or action under teststateUnderTest
— system state when object or action is being tested (usually starts withwhen
,after
,on
)expectedBehavior
— what we expect to see (always starts withshould
)
These mainly contain method wrappers for frequently used and complicated UI or device-specific actions. It has waiters, view property getters, improved assert messages, syntactic sugar, etc.
EspressoExtensions.java
|EspressoExtensions.kt
— custom Espresso-like methods/functions (also, consider Kaspresso)UiAutomatorExtensions.java
|UiAutomatorExtensions.kt
— custom methods/functions to work with UI Automator's API, mostly withUiObject2
UI elementsAndroidExtensions.java
|AndroidExtensions.kt
— device-specific actions
One possible way to integrate your tests with Test Management System is to report test results during test execution. For this one can use JUnit RunListener API.
There is an implementation of such Listener to report to TestRail: ReporterRunListener.java
.
To make it work you need to:
- Add TestRail API bindings to your project (unfortunately, you can't add it as a dependency yet)
- Create
AndroidManifest.xml
for a test app - Annotate your tests with Test Case ID from TestRail (you need a custom Annotation for this):
@Test
@CaseId(1)
public void your_test_name() { }
There are configured linters for both languages:
- Java: checkstyle. To run, execute
gradlew checkstyle
command in Terminal - Kotlin: ktlint. To run, execute
gradlew ktlint
command in Terminal