paint-brush
Why Your Project Needs Screenshot Testingby@traz9g
115 reads New Story

Why Your Project Needs Screenshot Testing

by Artsiom SeliuzhytskiMarch 24th, 2025
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Screenshot testing is a simple but important way to check UI quality in Android apps, especially for complex designs and different languages. Tools like Paparazzi are fast, reliable, and work well with CI/CD pipelines, making it a great choice for testing visual issues. Unlike older tools like Shot, which are slow and require more resources, Paparazzi runs quickly and without problems. Adding screenshot testing to your CI/CD pipeline helps catch visual bugs early, speeds up code reviews, and improves team collaboration. If you’re not using it yet, it’s time to start.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Why Your Project Needs Screenshot Testing
Artsiom Seliuzhytski HackerNoon profile picture
0-item

For the past six years, I have been actively using screenshot testing on every project I work on – whether it's a large production project or a pet project where I'm testing a new concept or naively trying to solve yet another problem that nobody asked about. Every time, this tool has proven to be reliable and useful, especially considering how easy it is to add it to a project and how little time it takes to maintain.

Let me explain everything step by step.

Why I believe every project requires screenshot testing

Surprisingly, not many projects use screenshot testing, even though it’s the cheapest way to verify the UI integrity of an app. With the right setup, covering additional screens takes about 5-10 minutes, but it stays there forever and serves as a reliable indicator of whether the screen looks as expected. And with the right architecture, you can easily cover every possible UI state for the entire app. I just want to pause for a moment here and emphasize this – every state of the UI.

Why is this a big deal? Having a test suite with 100% UI coverage and saved screenshots opens up new ways to perform day-to-day tasks.

How it works

Before we go further, let me explain the main concept behind screenshot testing. Basically, the idea is to capture the UI – creating "golden standard" screenshots – and use these screenshots whenever we make changes to the codebase. Quite simple, right?

Of course, you can do it manually – and many teams do this on a daily basis by comparing the app with Figma – but I strongly believe it’s much easier to automate this process rather than manually checking the UI yourself, especially considering how easily some bugs can slip through.

Manual testing

How long will it take for the whole team to test each possible UI state for your app? A couple of hours? No, no, no – I mean EVERY possible state: every dialog, bottom sheet, options dialogs, errors, warnings, "something went wrong" screens, loading screens, retries, etc. I guess at this point, it’s more like a couple of days. But if you want to check it on more than one device – let’s say an average phone, a foldable device, and a tablet – now we need to double that time. Do you localize the app? Let’s test it in every language you support to make sure every button and dialog can still fit the text. And to be 100% sure, let’s test it again on an average phone, foldable device, and tablet. Are you still tracking the time? But we’re not done yet. On top of that, let’s test accessibility with different font sizes, on devices with different screen sizes, and in different languages. Do you see where this is going? The complexity grows exponentially.

But what if I told you that you can do the same job in less than 15 minutes?

Cases where screenshot tests proved to be useful

But all the text above was a bit abstract, without any real-life examples. Yes, you can integrate the tool and automate something, but how does it actually make your life easier?

Well, the first example is just day-to-day tasks, where you need to fix a bug or add a small feature to an existing screen. When you finish your task and update the screenshots in the project, they conveniently pop up in the PR, and the rest of the team can visually see your changes. Or, they might not see any changes, which can serve as proof that a bug fix didn’t cause any issues. And believe me, this speeds up the review process so much. People tend to prioritize the review when they can understand the context of the changes, and if they can see the UI, it’s the most efficient way to provide that context.

Another case – app redesign. Whether or not your team wants to change the UI permanently, make a temporary collaboration with another brand, or work on a Christmas mode – the app should be carefully tested before it goes live. If the product requires more complexity, like feature flags or A/B tests, it becomes an impossible task to double-check everything. And if someone finds an issue at the last minute before the release… let’s be honest – the dev team will just check the affected screen and release the app, hoping that the fix didn’t break anything else. Retesting everything from the beginning would make managers very upset, especially if higher management was promised that the app would be released today.

It also saves a lot of time in cases like design system changes, UI library updates (especially if you have custom UI components), or the refactoring of reusable components, like alert dialogs or bottom sheet dialogs.

You might argue that your project already has unit tests and UI tests, so why should you bother adding another type of test and supporting it?

Comparisons with another type of tests

Unit tests are designed to test business logic, but there is no guarantee that the data checked by unit tests will be visible to the user. For example, the UI might not subscribe to the data update, meaning the only thing the user will see is a blank or loading screen. But you have UI tests to check that, right? UI tests verify that each UI element is present and visible on the screen.

The problem here is that UI tests can miss a lot of details – element colors, sizes, padding, transparency, etc. Additionally, to check each case, you might need to increase the complexity of the setup and introduce additional tests and mocks to verify modal dialogs for specific scenarios, error states, A/B tests, and so on.

With screenshot tests, it's much easier to check an additional UI state and add it to the test suite. And as a bonus, screenshot tests allow your team to simplify UI tests. Instead of checking whether each text, field, or button is present on the screen and verifying the state of each view and the text they contain, you can delegate that to the screenshot tests. This way, you can make your UI tests more lightweight. Rather than checking all UI elements, you can focus on testing the integration by simply navigating to the screen, ensuring it’s the correct screen, and confirming that there are no crashes.

Testing pyramid and how screenshot testing fits into it

Testing pyramid

For me, it’s something that sits between unit tests and UI tests. You can think of it as a unit test for the UI: it’s still relatively easy to implement and covers a specific UI state for a single screen. And it’s very cheap to execute, just like a unit test. There’s no need to mock the entire app or run the emulator to test it. Additionally, modern screenshot testing libraries utilize unit test frameworks under the hood.

Libraries for the Android platform

Are you starting to become more interested in the topic? Let’s talk about the code.

At the moment, there are three major options for adding screenshot tests to your project: Shot, Paparazzi, and Compose Preview Screenshot Testing libraries. If your app is still heavily reliant on Views and XML, you have two options: Shot and Paparazzi libraries. For Compose, you can use Paparazzi or Compose Preview Screenshot Testing.

  • Shot – A very mature and feature-rich library, but it lacks in performance. It works by using UI tests: you need to prepare an Espresso UI test, set up the screen, mock data, put the screen in the right state, and then call the compareScreenshot(activity/fragment) method to capture and compare the screenshot with the baseline. More details can be found here: Shot GitHub.

    Doesn’t sound easy? In that case, I would strongly recommend checking out the next library.

  • Paparazzi – A simpler and more modern approach. Instead of running the emulator and creating UI tests, you just need to create a unit test and copy your preview. Yes, it’s that simple.

    More details can be found here: Paparazzi GitHub.

  • Compose Preview Screenshot Testing – An even more modern and simpler approach. To create a new test, you just need to create a new unit test in the screenshotTest source set, copy your existing Preview, and that’s it. But as you might guess, it only supports Compose, so your entire project should use Compose for the UI to achieve good coverage. It doesn’t prevent you from covering new screens if you’re in the process of migration, but you’ll need to prioritize it, which can be challenging for the business.

    More information can be found here: Compose Screenshot Testing.

A couple of words about performance

In my current project, I have more than 200 screens and over 1,200 tests to cover the entire app. It takes around 10 minutes to verify the entire test suite for screenshot tests on a MacBook Pro with an M2 Pro chip (not the highest spec). Sounds good, right? Especially when you consider how much time it would take to test everything manually.

Another case – my pet project for a driving theory app. It has around 700 questions in the question bank, but with screenshot tests, it was very easy to cover the entire dataset and ensure the UI looks perfect for each question. The best part – it took me just a couple of lines of code to implement it.

Why I believe Paparazzi is the best choice for now

For now, my obvious choice is the Paparazzi library. It offers the flexibility to cover both the View system and Compose. It also supports capturing animations, which I strongly recommend avoiding, but it’s nice to have this feature in case you need it. However, this can make the test suite a bit more flaky in certain scenarios.

Personally, I’m keeping an eye on Compose Preview Screenshot Testing, but for now, it doesn’t feel mature enough to start using in production. The comparison algorithm is a bit worse than the one in the Paparazzi library, which requires increasing the threshold. This can lead to the possibility of missing small issues, like a slight change in padding or incorrect wording, which might slip through the CI/CD checks. But it’s definitely worth migrating to in the future, as it’s something Google is working on, which means good support in the long term.

Conclusion

When screenshot testing becomes part of your daily routine, it changes the way you work. You can experiment more with your codebase without the doubt of breaking anything in the project. It helps with large refactorings because, from now on, you have a tool that ensures your changes don’t break the app and that your users will see the UI that your design team intended. Your teammates can easily see the changes during the code review process. And all of this can be achieved by spending just an additional 10 minutes adding a couple more tests to the project for each ticket. Plus, your company doesn’t need to hire additional QA engineers to verify your work, saving resources and allowing the company to focus more on growth.