liveBook · Manning

AppTest

As explained in Build Python Web Apps with Streamlit

AppTest is Streamlit's testing API for creating and programmatically interacting with a runnable app instance without displaying its browser interface.

A Streamlit app can look right until a user enters a search term and clicks a button. AppTest lets a Python test run the app, simulate those actions, and inspect its output without opening a browser. section 11.4

A frontend test follows a short cycle:

  • Create a runnable app with AppTest.from_file("frontend.py"). Set test secrets if the app needs them, then call run() to start it. section 11.4.1
  • Find elements by type, such as at.sidebar.text_input or at.sidebar.button. Use set_value(...) or click(), followed by run() to trigger a rerun. section 11.4.1 section 11.8
  • Assert what changed in session_state and in rendered elements such as expanders or markdown. section 11.4.1
Listing 11.7 Testing the frontend
import pytest
from unittest.mock import patch
from streamlit.testing.v1 import AppTest
from mock_data import MOCK_RESULTS

class MockBackend:
  @staticmethod
  def get_poster_url(path):
    return "https://mock-image-server.com/poster.jpg"

  def __init__(self, api_key):
    self.api_key = api_key

  def search_movies(self, query):
    return MOCK_RESULTS

@pytest.fixture
def setup_app():
  at = AppTest.from_file("frontend.py")
  at.secrets["api_key"] = "test_api_key"
  return at

@patch("backend.Backend", MockBackend)
def test_initial_state(setup_app):
  at = setup_app
  at.run()

  # Check if sidebar has search input field and button
  assert len(at.sidebar.text_input) == 1
  assert len(at.sidebar.button) == 1
  assert "Search" in at.sidebar.button[0].label

  # Check that results are not visible initially
  assert "results" not in at.session_state
  assert len(at.expander) == 0

This complete starting-state test shows a pytest fixture creating the app, supplying a test API key, and checking the sidebar before any search. A patched backend keeps this frontend test independent of the real backend. section 11.4.1

Test a search

After at.run(), enter a query with at.sidebar.text_input[0].set_value("test movie").run(), then press at.sidebar.button[0].click().run(). With a mock backend returning known results, assert that at.session_state["results"] matches those results and that the number of at.expander elements matches the number of movies. A separate display test checks movie overviews and ratings in at.markdown. section 11.4.1

AppTest also supports an end-to-end check. Run the app without replacing its backend, search for a real movie, and assert that results and their expanders appear. This checks the frontend, backend, and external API together rather than isolating the frontend. section 11.2.2 section 11.6

How Build Python Web Apps with Streamlit covers it

How deep it goes
Works through setup, reruns, interactions, and assertions, but does not explain AppTest internals.
Examples
Uses initial-state assertions, a mocked movie search, displayed movie details, and a live API search.
What it assumes
Assumes a Streamlit app to test and introduces the AppTest setup and interaction calls through pytest examples.
What you can do after
Apply it via Streamlit’s AppTest to simulate searches and assert frontend or end-to-end results.
How it connects
Connects frontend unit tests with pytest fixtures, mocking, session state, integration tests, and end-to-end tests.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Build Python Web Apps with Streamlit. The section links point to the parts of the book it draws on.