Testing: runner.invoke reuses 'app' object, causing cached properties to exist when they're not supposed to #1318
-
First Check
Commit to Help
Example Codefrom typer.testing import CliRunner from .main import app runner = CliRunner() def test_list_databases() -> None: # This command causes an internal 'databases' object to be cached. result = runner.invoke(app, ["databases", "list"] assert result.exit_code == 0 def test_create_database() -> None: # This command accesses some cached properties (using cached-property package). # Those objects aren't supposed to exist yet, but they were already created in previous tests. # This causes the command to use old data and crash. result = runner.invoke(app, ["databases", "create", "tests-db", "MariaDB"]) assert result.exit_code == 0DescriptionCliRunner.invoke reuses 'app' causing different behavior than just running them outside tests. My code uses some cached properties that get cached in earlier tests. Operating SystemLinux Operating System DetailsNo response Typer Version0.4.0 Python Version3.7 Additional ContextNo response |
Beta Was this translation helpful? Give feedback.
Answered by YuriiMotov Sep 17, 2025
Replies: 2 comments 1 reply
-
| happening for me as well, some options get cached and re-used in the following tests, making the tests fail |
Beta Was this translation helpful? Give feedback.
0 replies
-
| This is not a Typer's issue.. You can solve this by re-importing the app on every test: import helloworld.main ... def test_list_databases(): importlib.reload(helloworld.main) result = runner.invoke(helloworld.main.app, ...) ...Working code examplehelloworld/main.py from functools import cached_property import typer class DatabaseManager: @cached_property def databases(self) -> list[str]: print(">> Creating databases list") return ["default-db"] def create(self, name: str) -> None: print(f">> Creating database {name}") self.databases.append(name) manager = DatabaseManager() app = typer.Typer() @app.command() def list_databases(): for db in manager.databases: typer.echo(db) @app.command() def create_database(name: str): manager.create(name) typer.echo(f"Database {name} created")helloworld/test.py import importlib from typer.testing import CliRunner import helloworld.main runner = CliRunner() def test_list_databases(): importlib.reload(helloworld.main) result = runner.invoke(helloworld.main.app, ["list-databases"]) assert result.exit_code == 0 assert ">> Creating databases list" in result.stdout def test_create_database(): importlib.reload(helloworld.main) result = runner.invoke(helloworld.main.app, ["create-database", "test-db"]) assert result.exit_code == 0 assert ">> Creating databases list" in result.stdout |
Beta Was this translation helpful? Give feedback.
1 reply
Answer selected by YuriiMotov
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This is not a Typer's issue..
You can solve this by re-importing the app on every test:
Working code example
helloworld/main.py