Better Android Testing at Airbnb — Part 6: Consistent Mocking

Consistent Mocking

Eli Hart
12 min readintermediate
--
View Original

Overview

This article discusses the challenges of achieving consistent mocking in Android testing at Airbnb, focusing on common sources of flakiness and strategies to mitigate them. It highlights the importance of a stable test framework and shares specific solutions for various issues encountered during testing.

What You'll Learn

1

How to minimize flakiness in Android tests by managing shared state

2

Why consistent mocking is crucial for reliable automated testing

3

How to effectively handle asynchronous code in tests

4

How to clear shared preferences to avoid test interference

Prerequisites & Requirements

  • Understanding of Android testing frameworks and mocking
  • Familiarity with dependency injection frameworks(optional)

Key Questions Answered

What are the common sources of flakiness in Android testing?
Common sources of flakiness include asynchronous code execution, cached state in views, shared preferences affecting mocks, and variations in drawable resources. These issues can lead to inconsistent test results and require specific strategies to mitigate.
How can shared preferences affect Android tests?
If one mock changes shared preferences, it can affect subsequent mocks, leading to inconsistent test results. To address this, the test framework should clear shared preferences after each mock to ensure a clean state for each test.
Why is mocking dates important in Android testing?
Mocking dates is crucial because UI code often references the current time, which can lead to flakiness in tests. By using a consistent mocked value for dates, tests can avoid variations that affect screenshots and interaction reports.
How does the article suggest handling drawable flakiness?
To handle drawable flakiness, the article suggests forcing the drawable cache to clear after each screenshot. This ensures that tests do not encounter variations in cached bitmaps, which can lead to inconsistent results.

Technologies & Tools

Library
Rxjava
Used for asynchronous programming in the application.
Library
Kotlin Coroutines
Used for managing asynchronous tasks in a more structured way.
Library
Jodatime
Used for consistent date mocking in tests.

Key Actionable Insights

1
Implement a consistent mocking strategy across all product features to reduce flakiness.
By enforcing uniform patterns and architecture, you can address sources of flakiness in a scalable manner, allowing fixes to be applied universally across the codebase.
2
Utilize dependency injection to manage asynchronous code execution in tests.
This approach allows the test framework to control when asynchronous operations are executed, minimizing unexpected side effects that can lead to test failures.
3
Regularly clear shared preferences and other storage types between tests.
This practice prevents state leakage from one test to another, ensuring that each test runs in isolation and produces reliable results.
4
Adopt a centralized image loading architecture to streamline testing.
By controlling image loading through a single point, you can easily mock image resources and reduce variability in test outcomes.

Common Pitfalls

1
Failing to manage shared state between tests can lead to inconsistent results.
When tests share state, the outcome of one test can inadvertently affect another, resulting in flakiness. It is crucial to isolate tests by clearing shared state to maintain reliability.
2
Not properly handling asynchronous code can introduce unpredictability.
If asynchronous operations are not controlled, they can lead to unexpected side effects that cause tests to fail. Implementing a strategy to manage these operations is essential for stable testing.