Mobile Development 17 min read

Airbnb’s Android Automation Testing Framework: State Simulation with MvRx (Part 1)

Airbnb’s new Android automation testing framework replaces flaky Espresso tests with deterministic UI rendering by simulating immutable State objects via MvRx, Epoxy, and a custom DSL, enabling fast, reliable tests, easy mock generation, and a launcher for instant screen inspection across multiple state variants.

Airbnb Technology Team
Airbnb Technology Team
Airbnb Technology Team
Airbnb’s Android Automation Testing Framework: State Simulation with MvRx (Part 1)

This article is the first of a seven‑part series describing how Airbnb built an Android automation testing framework based on the MvRx library and a custom state‑simulation system.

Initially, Android UI testing at Airbnb relied on manual testing and Espresso. Espresso proved costly and flaky due to difficulties in mocking network requests, tightly coupled UI and business logic in Fragments, and high maintenance overhead as the app grew.

To achieve reliable, fast, and high‑coverage UI tests, the team introduced a state‑simulation approach. Each Fragment’s UI is rendered purely from an immutable Kotlin data class called State . By providing a specific State instance, the UI becomes deterministic and easy to test.

Key components introduced:

MvRx – a Jetpack ViewModel‑based architecture that stores UI state in immutable data classes.

Epoxy – a declarative UI builder that works seamlessly with MvRx.

A DSL for defining State variants (e.g., Loading, Empty results) and for modifying nested properties.

Simple "Hello World" example (code kept intact): data class MyState(val text: String = "Hello World") : MvRxState class MyViewModel(state: MyState) : BaseMvRxViewModel (state) class MyFragment : MvRxFragment() { val viewModel: MyViewModel by fragmentViewModel() fun epoxyController() = simpleController(viewModel) { state -> textRow { id("title") text(state.text) } } } The framework registers mock implementations for each ViewModel via provideMocks() . Example for a fragment showing a list of jokes: class DadJokeFragment : MvRxFragment() { val viewModel: DadJokeViewModel by fragmentViewModel() override fun provideMocks() = mockSingleViewModel( viewModelReference = DadJokeFragment::viewModel, defaultState = mockDadJokeState ) } The default mock State is defined as a Kotlin data class: val mockDadJokeState = DadJokeState( jokes = Success( value = JokesResponse( nextPage = 3, results = listOf( Joke(id = "0LuXvkq4Muc", joke = "I'm tired of following my dreams..."), Joke(id = "0ga2EdN7prc", joke = "Did you hear about the guy whose whole left side was cut off? He's all right now."), Joke(id = "0oO71TSv4Ed", joke = "Why didn't the skeleton cross the road? Because he had no guts.") ) ) ) ) For complex screens, a command‑line Kotlin script can generate the full State construction code via reflection, storing the generated Kotlin files back into the project’s mocks package. The DSL allows concise definition of State variants. Example: override fun provideMocks() = mockSingleViewModel( viewModelReference = DadJokeFragment::viewModel, defaultState = mockDadJokeState ) { state("Loading") { copy(jokes = Loading()) } state("Empty results") { copy(jokes = Success(jokes.copy(results = emptyList()))) } } Nested property modifications are simplified with the DSL’s set helpers, e.g.: state("Show cancellation policy subtitle") { set { ::bookingDetails { success { ::cancellationSection { ::showSubtitle } } } }.with { true } } A launcher activity lists all Fragments and their mock variants, allowing developers to jump directly to any screen with a chosen State, dramatically speeding up UI iteration and testing. The article concludes by noting that the simulation system and launcher have been open‑sourced as part of the MvRx library (since version 2.0.0‑alpha) and previews the next part, which will cover automated screenshot testing.

AndroidKotlintesting frameworkAutomation TestingEpoxyMvRxState Simulation
Airbnb Technology Team
Written by

Airbnb Technology Team

Official account of the Airbnb Technology Team, sharing Airbnb's tech innovations and real-world implementations, building a world where home is everywhere through technology.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.