Overview

11 Testing Streamlit apps

This chapter explains why testing is essential for building reliable Streamlit applications, especially once an app grows beyond a small personal project. It uses a simple movie-search app as the running example: a Streamlit frontend accepts a user’s search query, a backend calls a movie database API, the response is transformed into a convenient format, and the frontend displays movie details such as titles, release years, posters, overviews, and ratings. The chapter frames testing as a way to catch bugs before users do, protect existing features from accidental breakage, and make professional apps more dependable.

The chapter introduces a layered testing strategy using pytest. It distinguishes manual testing from automated testing, then focuses on unit, integration, and end-to-end tests. Backend unit tests isolate the backend from external dependencies by mocking API calls and fake responses, allowing tests to verify request behavior, response parsing, empty result handling, and poster URL generation without relying on the real network. Frontend unit tests use Streamlit’s AppTest to run the app in a simulated environment, inspect UI elements, manipulate session state, enter text, click buttons, and verify rendered output. These tests also demonstrate how a subtle bug—using the wrong key for a movie rating—can be caught even when the app does not crash.

The chapter then expands from isolated tests to broader validation. Integration tests check that the frontend and backend work together while still mocking the external API, and separately verify that the backend can communicate with the real API. An end-to-end test removes mocks entirely and simulates a real user search through the whole app, confirming that results appear and are rendered correctly. Finally, the chapter emphasizes that tests should evolve alongside the application: when code changes, failing tests may indicate either broken functionality or outdated test expectations, and new features should bring new tests. It also encourages running tests frequently, selectively when needed, and automatically through development workflows so the test suite remains an active guard against regressions.

The design for the MovieScout app.
Screenshot of the working MovieScout app (see chapter_11/in_progress_01 in the GitHub repo for the full code).
The requests module and the TMDB API are external dependencies of Backend.
How a unit test works.
Flowchart showing how your app code and test code evolve.

Summary

  • Testing your code can help you catch bugs before they reach your users and harden your application against failures.
  • st.image can be used to render images in a Streamlit app.
  • Automated testing consists of writing test code to check if your app code works correctly.
  • Automated tests include unit tests, integration tests, and end-to-end tests.
  • pytest is a popular framework for testing Python scripts and apps.
  • Unit testing requires isolating the component under test from any dependency external to it, controlling its behavior by mocking it—i.e., swapping it out for a fake version.
  • A test function runs the component under test—with mocked dependencies—and compares the actual results with the expected ones.
  • You should write as many tests as needed for each component you want to check.
  • A fixture is a reusable component that provides specific features to tests; pytest offers a @pytest.fixture decorator to mark a function as a fixture.
  • The @patch decorator from unittest.mock can be used to mock a real dependency, replacing it with a fake.
  • An assertion is a condition that is evaluated during a test; for a test to pass, all assertions must be true.
  • You can run tests in pytest using the pytest command, adding the -v flag for verbose output.
  • Streamlit's AppTest class simulates a running Streamlit app built from your code and has methods to mimic user interaction and inspect the rendered output.
  • AppTest.from_file(...) creates a runnable instance of your Streamlit app, which can be started by calling its run() method.
  • You can use dot notation on the AppTest instance to access lists of Streamlit elements of a particular type—for instance, at.button returns a list of buttons.
  • You can simulate a user interaction on an element with methods such as set_value(...) and click(), chaining a call to run() to manually trigger an app re-run.
  • Integration tests check how components behave when they are used together.
  • An end-to-end test verifies the entire flow of an app under real-world conditions, with no mocking.
  • As your app evolves, you should update your tests to match.
  • You can automate test runs with a Git pre-commit hook; you can even set up CI tools like GitHub Actions to run tests automatically when code is pushed.

FAQ

Why is testing important for Streamlit apps?Testing helps ensure that a Streamlit app works correctly when users enter unexpected data, when external APIs change, or when new code accidentally breaks existing behavior. Automated tests catch bugs before users do and give you confidence that the frontend, backend, and external dependencies behave as expected.
What example app is used in chapter 11 to demonstrate testing?The chapter uses MovieScout, a simple Streamlit app that lets users enter a movie search query and displays matching movie results. The frontend collects the query and renders results, while the backend calls the TMDB API, parses the response, and returns movie data keyed by movie ID.
What are the main types of tests discussed in the chapter?The chapter discusses unit tests, integration tests, and end-to-end tests. Unit tests check individual functions or components in isolation. Integration tests verify that multiple components work together, such as the frontend with the backend or the backend with the API. End-to-end tests validate the full application flow under realistic conditions.
What is the recommended testing approach for the MovieScout app?The chapter uses a bottom-up testing approach. It starts with backend unit tests, then frontend unit tests using Streamlit’s AppTest, then integration tests between components, and finally an end-to-end test that exercises the whole app without mocks.
What role does pytest play in testing Streamlit apps?pytest is used to write and run automated tests. It provides concise syntax, automatic test discovery, useful failure reports, fixtures for reusable setup code, and support for assertions. Tests are run from the terminal with commands such as pytest -v, where -v enables verbose output.
What is mocking, and why is it used in backend unit tests?Mocking replaces real external dependencies with controlled fake versions during tests. In the MovieScout backend tests, requests.get and API responses are mocked so the tests do not make real network calls to TMDB. This makes unit tests faster, deterministic, independent of network conditions, and focused only on the behavior of the Backend class.
How does Streamlit’s AppTest help test the frontend?AppTest creates a simulated running Streamlit app from a file such as frontend.py. It allows tests to inspect rendered elements like text inputs, buttons, markdown, and expanders, and to simulate user interactions such as setting a text input value or clicking a button. After interactions, tests call .run() to trigger the rerun that would happen in a real Streamlit app.
How are frontend unit tests isolated from the backend?The frontend tests replace the real Backend class with a MockBackend. This mock class has the same basic interface as the real backend but returns predefined movie data and a dummy poster URL. This ensures frontend unit tests are not affected by backend logic, network calls, or TMDB API behavior.
What bug did the frontend tests reveal in the MovieScout app?The frontend tests revealed that the app tried to display movie ratings using movie.get('rating', 'N/A'), but the TMDB response and mock data use the key vote_average. Because the code supplied a default value of N/A, the bug failed silently in the app, but the test caught that the expected rating text was missing.
How should tests evolve as the application code changes?Tests should be run whenever the code changes. If a test fails, either the code change broke existing functionality and the app code must be fixed, or the app’s intended behavior changed and the tests must be updated. New features should also come with new tests. In this way, application code and test code evolve together to maintain a reliable production app.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Build Python Web Apps with Streamlit ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Build Python Web Apps with Streamlit ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Build Python Web Apps with Streamlit ebook for free