Android Unit Test nomenclature
In this blog post, I will introduce you to the first testing pattern we’ve adopted in our Android app at Gousto: unit test naming conventions.
Our architecture is divided into 3 layers: Presentation, Domain and Data.
- Data: holds any sort of processing and mapping of raw data coming from any internal sources (shared preferences, Database) and external sources (Gousto API)
- Domain: the business logic divided into use cases
- Presentation: the UI (activities, fragment, views) and UI scenarios logic (presenters)
Our unit tests are covering the entirety of the Data, Domain and presentation layers. The UI itself is covered using the automated testing framework Espresso.
With such an architecture and so many components, we needed first to have the ability to write unit tests covering any kind of regression (our approach to testing), we then use common testing patterns to give us high level of confidence in the code we produce
The first pattern we’ve started to follow is unit test naming conventions.
There are only two hard things in Computer Science: cache invalidation and naming things.
— Phil Karlton
Naming things becomes very easy when you start to describe their behaviour.
Naming Conventions
In the Android team, we write our regular unit tests using the following naming convention:
@Test
Should_ExpectedBehavior_When_StateUnderTest()
This behaviour oriented approach is very close to human language, which makes it easier to understand a failing test.
Also, describing unit tests by behaviour creates a natural documentation of our app and its expected behaviour in specific conditions. It’s therefore very helpful for new joiners or as a reminder.
Programs are meant to be read by humans and only incidentally for computers to execute.
— Donald Knuth
Here are some examples:
@Test
Should_ShowCachedFoodAndShowAnError_When_FoodIsInCacheAndFetchingFails()@Test
Should_FetchDeliveryDays_When_PostcodeIsValid()@Test
Should_ReturnError_When_PostcodeVerificationOrDaysFetchingFails()@Test
Should_ReturnTrue_When_TokenIsValid()@Test
Should_ReleaseResources()
Note: The state under test is not always required if the test is clear enough without it
Network Requests
We have a different naming convention when testing our network requests. They are covered by strict regression tests and the APIs have a clear pattern:
@Test
apiRequest_When_StateUnderTest_With_Parameters()
Examples:
@Test
postcodeLookup_When_ValidRequest_With_Postcode()@Test
updateShippingAddress_When_ValidRequest_With_AllParameters()@Test
deleteShippingAddresses_When_ValidRequest()
Going Further
Kotlin introduced backtick quotes which allows us to write a method name with the same structure as a human language sentence, as long as the `name is escaped with quotes`.
This new feature would allow us to write testing methods even closer to human language. The method would instead literally describe the test.
Instead of this:
@Test
Should_CreateAWineBottleAndAddItToUserBasket_When_UserHasLegalAgeLimit()
We would’ve this:
@Test
`Create a new wine bottle in the user basket when he is above the legal age limit`()
However this approach doesn’t work when running UI tests with AndroidJUnit. Backtick quotes work fine on their own, but as soon as an exotic character such as a space comes in, the compilation dramatically fails.
The recipe for a good testing naming convention:
- The closer to human language it is, the more maintainable and self-documented the code will be
- Network request tests should use an explicit naming scheme
- Kotlin’s backtick quotes can potentially make the tests even more human friendly (with a few small restrictions)