An Introduction to Paparazzi for Snapshot Testing
Tags: android, ui, testing, jetpackcompose
Published: 2023-08-10 10:18:31

---
title: An Introduction to Paparazzi for Snapshot Testing
published: true
date: 2023-08-03 05:28:36 UTC
tags: Android, UI, Testing, JetpackCompose
canonical_url: https://hameteman.com/an-introduction-to-paparazzi-for-snapshot-testing
---
![An Introduction to Paparazzi for Snapshot Testing](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zibconslpzfjkwqty7hw.png)

> TL;DR: Snapshot testing with Paparazzi allows you to ensure your Jetpack Compose components behave as expected, without needing an emulator. This article covers setting up Paparazzi, creating a simple Tag composable, and using Paparazzi to create, verify, and update snapshot tests for your Android app.

### What is Snapshot Testing?

Snapshot testing allows you to ensure that your output continues to behave as expected. This is useful because as you revisit your code, some changes might cause something to break.

When writing snapshot tests for Jetpack Compose components, you first need to have your code in a working state. Then generate a snapshot of its expected output given certain data. The snapshot tests are committed alongside the component.

[Paparazzi](https://github.com/cashapp/paparazzi) is an Android library you can use to create those snapshots for your apps in a simple and friendly way and compare them. One of the advantages this library has over its competitor [Shot](https://github.com/pedrovgs/Shot) is that it doesn't need an emulator to run the tests, it just runs in the unit test stage which is _much_ faster.

{% github https://github.com/cashapp/paparazzi no-readme %}

### Set up

Let's begin the setup process for our first test! To get started, we need to make some changes to the root `build.gradle` file. First, we'll add the necessary dependency for Paparazzi and apply the plugin. The latest version available at the time of writing is 1.3.1.

The `build.gradle` file should look like this after adding the dependency:

```
buildscript {
    // ... Repositories and other settings
    dependencies {
        classpath 'app.cash.paparazzi:paparazzi-gradle-plugin:1.3.1'
        // ... Other dependencies
    }
}

// ... The rest of your build.gradle content

apply plugin: 'app.cash.paparazzi'

```

Next, in your Android library or app module, we need to include the Paparazzi plugin in the plugins block within `build.gradle`:

```
plugins {
    // Other plugin ids
    id 'app.cash.paparazzi'
}

```

After making these changes, perform a Gradle sync to complete the setup process. Now, we are all set to create our first snapshot using Paparazzi!

### Creating the first snapshot test

Let's create a simple Tag composable of which we can make a snapshot later on. Normally a component like this would also have support for click interactions and accessibility. For brevity, we will leave these out in this example.

```
@Composable
fun Tag(
    name: String,
    modifier: Modifier = Modifier,
    backgroundColor: Color = MaterialTheme.colors.primarySurface,
    contentColor: Color = contentColorFor(backgroundColor)
) {
    Text(
        text = "#$name".toLowerCase(Locale.current),
        modifier = modifier
            .background(
                color = backgroundColor,
                shape = MaterialTheme.shapes.small
            )
            .padding(horizontal = 4.dp, vertical = 2.dp),
        color = contentColor,
        fontSize = 12.sp
    )
}

```

This will end up in a component looking like this:

![A purple tag with the word tag on it](https://cdn.hashnode.com/res/hashnode/image/upload/v1690953159374/44670216-e6c4-4c03-8c02-4eef08c2a339.png)

Next, let's create the snapshot test. Create a new test and make sure to place it inside the `unitTest` folder instead of `androidTest`.

In the `TagTest` class, add the Paparazzi rule, use rendering mode `SHRINK` here if you only want to capture the component instead of the whole screen of the device.

```
@get:Rule
val paparazzi = Paparazzi(
    deviceConfig = DeviceConfig.NEXUS_5.copy(softButtons = false),
    renderingMode = SessionParams.RenderingMode.SHRINK
)

```

Create a test to render the component like so;

```
@Test
fun testTag() {
    paparazzi.snapshot("Tag") {
        MaterialTheme {
            Tag(name = "Snapshot-Test")
        }
    }
}

```

Because we've added Paparazzi to the Gradle files already, there are now 2 additional tasks that you can run.

1. `verifyPaparazziDebug` -- Runs tests and verifies against previously-recorded golden values. Failures generate diffs at `build/paparazzi/failures`.
2. `recordPaparazziDebug` -- Saves snapshots as golden values to a predefined source-controlled location (defaults to `src/test/snapshots`).

Because we haven't created the golden values yet, running the verify task now will result in a failed test.

```
$ ./gradlew :app:verifyPaparazziDebug

> Task :app:testReleaseUnitTest

com.appsoluut.paparazzi.tag.TagTest > testTag FAILED
    java.lang.AssertionError at TagTest.kt:19

* What went wrong:
Execution failed for task ':app:testReleaseUnitTest'.
> There were failing tests. See the report at: file://android/paparazzi/app/build/reports/tests/testReleaseUnitTest/index.html

```

Creating the golden values is simple. Look at the tasks table above and see you only need to run the `recordPaparazziDebug` task to start recording. If it doesn't already exists, a new `snapshots` folder will be created in the `src/test` directory. This will contain our snapshot and should look something like this.

![Golden value snapshot](https://cdn.hashnode.com/res/hashnode/image/upload/v1691039337150/a2c56181-55a3-4355-a2b9-9cd93ab1ee1f.png)

If you would run the `verifyPaparazziDebug` task again, all tests should report successfully. But let's make it more interesting and break the snapshot! Remove the `.toLowerCase(Locale.current)` part from the Tag composable so we have minimal changes. Run the `verifyPaparazziDebug` task again and see what happens.

```
> Task :app:testDebugUnitTest FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:testDebugUnitTest'.
> There were failing tests. See the report at: file://android/paparazzi/app/build/reports/tests/testDebugUnitTest/index.html

```

Unsurprisingly the test failed. You can either open up the HTML report and get a written report of what was going wrong, but that one will only tell you the percentage difference or if the size has changed of the snapshot.

More interesting is to see the actual difference in the snapshot. The tasks will now have created 2 output files which can be found in the `build/paparazzi/outputs` directory. The `delta` variant will show the expected, difference and actual snapshot in one handy image.

![Delta view](https://cdn.hashnode.com/res/hashnode/image/upload/v1691040059231/7a95f530-6dad-4322-b379-d7815dbc87f1.png)

It's directly clear from the above image what the problem is. If this was expected to change, you can just run the `recordPaparazziDebug` task again to update the golden values.

### Final words

I hope this article helped you get a basic understanding of snapshot testing and inspired you to add them to your project. The next part in this series will be adding the tests to be part of your CI/CD setup.