How can you (py-)test your code?

After having explored and experimented with Streamlit the next step is to refactor and mature my code.

So now i’m wondering. What’s best practice for testing parts of my code? I guess I would start to refactor some of my code into component functions. A hypothetical example is

import streamlit as st

def write_author(author: str):
    st.write(f"Author: {author}")

How can I use pytest to test this?

One option is pytest-selenium. But that is cumbersome, error prone and slow to do.

Another option might be mocking st.write

A third would be having something similar to the pytest-django client.

Is there something awesome or magical I can do?

Thanks.

2 Likes

Hey @Marc,

Unfortunately, there’s nothing particularly awesome or magical for doing this (unless you’re quite enamored of testing frameworks)!

For our code, we use a mix of unit tests (via pytest and Jest for Python and JavaScript/TypeScript, respectively), and end-to-end tests via Cypress.

If you download the Streamlit repo, you can see our streamlit/scripts/run_e2e_tests.sh script that automates the end-to-end testing process. This script iterates all tests in the streamlit/e2e/ folder.

Each test is comprised of two files: a streamlit/e2e/scripts/{test_name}.py Python file, and a streamlit/e2e/specs/{test_name}.spec.ts TypeScript file.

For each test, that test’s Python file implements a barebones Streamlit app that uses the functionality being tested, and its TypeScript component asserts that the resultant web page looks like it should.

The run_e2e_tests script does two things for each test:

  • streamlit run e2e/scripts/{test_name}.py. This runs the Python component via streamlit
  • yarn cy:run --spec e2e/specs/{test_name}.spec.ts This fires up Cypress and tells it to run the corresponding TypeScript test component.

You can use Cypress to automate interaction, to test that the interactive bits of your frontend cause your app to re-run and update in the expected way.

Hey @tim

Thanks for you feedback. If I could somehow st.get_frontend_document() from the frontend it would be rather easy to setup a test framework in the backend (i believe). I will post a feature request.

Created a feature request https://github.com/streamlit/streamlit/issues/432

Hi @tim

I’ve now refactored the Awesome Streamlit Test Runner into the Awesome Streamlit Package at Pypi.

It can be pip installed using

pip install awesome-streamlit

It can be used as simple as

from typing import List
import awesome_streamlit as ast
from awesome_streamlit.testing.models import (
    TesTItem,  # Special Capitalization is due to PyTest
)


def test_items_collector() -> List[TesTItem]:
    """A function to collect a list of test items based on a set of hardcode testitems"""
    return [
        TesTItem(
            name="Spreadsheet",
            location=(
                "https://raw.githubusercontent.com/MarcSkovMadsen/awesome-streamlit/master"
                "/src/pages/gallery/contributions/marc_skov_madsen/spreadsheet.py"
            ),
        )
    ]


ast.testing.test_runner_app.write(test_items_collector=test_items_collector)

I’ve also included the Awesome Streamlit Test Runner in the Gallery at https://awesome-streamlit.org.