Roborazzi is a powerful tool for snapshot testing in Android, especially with Compose, and it works well for catching visual regressions early. That said, some parts of using it effectively aren’t immediately intuitive. Here are my top tips for writing reliable, maintainable snapshot tests with Roborazzi.
Tip 1: Standardize Device Configuration for Consistency.
Always set device qualifiers in your @Before setup method. Inconsistent screen sizes across tests lead to flaky failures and make it hard to compare snapshots. Standardizing ensures all tests run with the same screen dimensions and density, producing reliable, reproducible images.
@Before
fun setup() {
RuntimeEnvironment.setQualifiers("w360dp-h720dp-480dpi")
RuntimeEnvironment.setFontScale(1.0f)
// ... other setup
}
Why it’s good: This prevents flaky tests caused by different screen configurations and makes snapshot comparisons reliable across your team and CI/CD pipeline.
Tip 2: Use a Base Class to Eliminate Boilerplate.
Create a base snapshot test class to centralize common configuration and helper methods. This reduces code duplication and ensures consistency across all your snapshot tests.
abstract class BaseSnapshotTest {
protected val changeThreshold: Float = 0.05f
protected val resizeScale: Double = 0.5
protected val dispatcher = UnconfinedTestDispatcher()
@get:Rule
val composeTestRule = createAndroidComposeRule(
effectContext = dispatcher
)
protected fun captureScreenshot(fileName: String) {
composeTestRule.onRoot().captureRoboImage(
filePath = "src/test/screenshots/$fileName",
roborazziOptions = RoborazziOptions(
compareOptions = RoborazziOptions.CompareOptions(
changeThreshold = changeThreshold
),
recordOptions = RoborazziOptions.RecordOptions(
resizeScale = resizeScale
)
)
)
}
}
Why it’s good: This reduces duplication, makes configuration changes easier, and ensures all tests follow the same patterns, making your test suite more maintainable.
Tip 3: Wait for UI to Stabilize Before Capturing.
Always use runOnIdle or waitForIdle to ensure Compose has finished rendering before capturing your screenshot. This prevents capturing incomplete or mid-animation states.
composeTestRule.runOnIdle {
captureScreenshot("MyScreen_Content.png")
}
Why it’s good: This ensures you capture the final rendered state, not intermediate frames, which prevents false positives from timing issues and makes your snapshots accurate representations of the UI.
Though some snapshot tests can be flaky, these tips will help minimize that!