---
question: Can I pytest a workflow without an engine?
kind: task
via_web: na
via_cli: available
via_python: available
via_api: na
via_config: na
ref_cli: uv run pytest
ref_python: run(parameters)
prereq: You need a workflow class with `run` implemented. [Create a workflow](/user-guide/build/agents/creating-a-workflow) first.
next:
  - /capabilities/build/workflows/expose-as-a-tool
  - /capabilities/build/agents/test-an-agent
  - /capabilities/build/modules/test-a-module
---

# Test a workflow

A workflow test builds the class and calls `run` with a parameters instance, in `<Name>Workflow_test.py` next to the file. The engine skips `_test.py` files when it discovers workflows. Chatting with the live model is a different test: [Test an agent](/user-guide/build/agents/test-an-agent).

## Web UI

Not applicable. Nexus runs no tests. To try the workflow through an agent, see [Test an agent](/user-guide/build/agents/test-an-agent).

## CLI

### Run the test file

From the project root:

```bash
uv run pytest src/my_module/workflows/CustomersWorkflow_test.py
```

`uv run pytest src/my_module` runs every test of the module. Write the tests as in the [Python steps](/user-guide/build/workflows/test-a-workflow?via=python).

### Give it an engine when it needs one

A test that loads the engine, as in the last Python step, needs the project's services running. In a NATS project, `Engine()` connects to a broker: run one (`abi dev up` or `abi stack start`), or point `ABI_CONFIG_OVERLAY` at a YAML file that sets `nats: null`.

## Python

### Call `run` with parameters

No engine is needed when the class does not read the module's services:

```python title="workflows/CustomersWorkflow_test.py"
from my_module.workflows.CustomersWorkflow import (
    CustomersWorkflow,
    CustomersWorkflowConfiguration,
    CustomersWorkflowParameters,
)


def test_run():
    workflow = CustomersWorkflow(CustomersWorkflowConfiguration())
    result = workflow.run(CustomersWorkflowParameters(entity_id="42"))
    assert result is not None
```

### Mock what it calls

Replace the integration or the store the method calls, so the test needs no network and no data. A workflow that reads a service in `__init__`, such as `ABIModule.get_instance().engine.services.triple_store`, needs it patched before the class is built:

```python title="workflows/CustomersWorkflow_test.py"
from unittest.mock import MagicMock, patch


def test_run_with_a_mocked_store():
    store = MagicMock()
    store.query.return_value = [("Acme",)]
    with patch("my_module.workflows.CustomersWorkflow.ABIModule") as module:
        module.get_instance.return_value.engine.services.triple_store = store
        workflow = CustomersWorkflow(CustomersWorkflowConfiguration())
    assert workflow.run(CustomersWorkflowParameters(entity_id="42"))["labels"] == ["Acme"]
```

### Or load the engine

To test against the real services, load the module in a session fixture:

```python title="workflows/CustomersWorkflow_test.py"
import pytest
from naas_abi_core.engine.Engine import Engine


@pytest.fixture(scope="session")
def engine():
    engine = Engine()
    engine.load(module_names=["my_module"])
    return engine
```

Then build the workflow in tests that take `engine`. Check the tools too: `as_tools()` returns the names and argument schemas the agent sees.

## REST API

Not applicable. The API runs a workflow but has no test runner. To check the route by hand, call it as in [Run a workflow](/user-guide/build/workflows/run-a-workflow?via=api).

## Config

Not applicable. Tests are Python files, not `config.yaml` entries.

## What to test

- **One test per intent.** Each parameters combination that changes the result.
- **Validation.** A bad parameters instance raises a Pydantic `ValidationError` before `run` starts.
- **Tools.** The tool names and descriptions from `as_tools()`: the model picks a tool by them.
