Testing Utilities
Canvas SDK provides a streamlined testing environment and local database support to help developers test their plugins with real data, without needing to mock or manually configure anything.
This guide covers two key capabilities:
canvas[test-utils]
— a set of tools and dependencies for writing database-backed tests.- Database seeding in CLI — populate or reset your local database when running plugins locally.
Project Structure #
The recommended layout for plugin development is now scaffolded automatically by the canvas init
command. This structure ensures compatibility with Canvas testing tools and CLI features, and it’s strongly encouraged for all new plugin projects. We also recommend to use uv
for managing dependencies.
plugin-folder/
├── my_plugin/
│ └── ...
├── tests/
│ ├── __init__.py
│ └── test_example.py
└── pyproject.toml
Plugin Testing with Pytest #
Installing the test-utils
extra provides everything needed to test plugins with pytest. No additional setup is required.
Features #
pytest
ready out of the box.- Each test is wrapped in a transaction and rolled back automatically.
- Use actual models or prebuilt factories to generate test data.
- No need for mocks or fake database layers.
Installation #
Add the following to your pyproject.toml
:
[project]
dependencies = [
"canvas[test-utils]",
# other dependencies...
]
or install directly via uv
:
uv install canvas[test-utils]
You can now run your test suite using:
uv run pytest
Using Factories #
Factories simplify test data creation and follow the factory_boy
pattern.
from canvas_sdk.test_utils.factories import PatientFactory
def test_factory() -> None:
patient = PatientFactory.create()
assert patient.id is not None
Using Models Directly #
You can also create records manually using the model classes:
from canvas_sdk.v1.data.discount import Discount
def test_model() -> None:
Discount.objects.create(
name="10%",
adjustment_group="30",
adjustment_code="CO",
discount=0.10,
)
assert Discount.objects.first().pk is not None
Whether using a factory or model directly, your test will run inside a transaction and automatically roll back at the end.
Available Factories #
All factories are available from:
from canvas_sdk.test_utils import factories
Developers are encouraged to add new factories for their own models.
Local DB Seeding via run-plugin
#
You can run plugins locally with full access to the database using the CLI. Two options are available:
Option | Description |
---|---|
--db-seed-file | Path to a Python file that populates your database. Warning: It resets the database before running the seed file. |
--reset-db | Clears and recreates the database before running the plugin |
Seed the Database #
To seed your plugin’s database with test data:
canvas run-plugin my_plugin --db-seed-file ./seed.py
Example seed.py
:
from canvas_sdk.test_utils.factories import PatientFactory
from canvas_sdk.v1.data.discount import Discount
PatientFactory.create(first_name="Seeded", last_name="Patient")
Discount.objects.create(
name="20%",
adjustment_group="X",
adjustment_code="Y",
discount=0.20
)
Reset the Database #
To reset the database before running a plugin:
canvas run-plugin my_plugin --reset-db
This will remove the existing database (if present) and recreate a clean version.
Simulate Events #
After your database is set up, simulate incoming events with:
canvas emit
Run canvas emit --help
for more info.