# How to Run Tests for Open-Notebook: Complete pytest & Async Guide

> Learn how to run tests for open-notebook using pytest and async. Follow this complete guide to execute the full test suite from the repository root after installing dependencies.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: how-to-guide
- Published: 2026-06-13

---

**Open-Notebook uses pytest with async support; execute the full suite with `uv run pytest` from the repository root after installing dependencies via `uv sync --dev`.**

The open-notebook project is an async-first Python application (Python 3.11+) that relies on pytest as its testing framework. Located in the `lfnovo/open-notebook` repository, the test suite validates domain logic, FastAPI endpoints, and SurrealDB integrations. This guide covers every command and architectural detail you need to execute tests locally and interpret results.

## Prerequisites and Environment Setup

Before running tests, ensure your environment matches the project's requirements. The [`pyproject.toml`](https://github.com/lfnovo/open-notebook/blob/main/pyproject.toml) specifies Python 3.11+ and uses `uv` as the package manager.

Install all development dependencies (including `pytest`, `pytest-asyncio`, and coverage tools):

```bash
uv sync --dev

```

This command reads the dependency declarations in [`pyproject.toml`](https://github.com/lfnovo/open-notebook/blob/main/pyproject.toml) and installs the exact versions required for the test runner and async support.

## Quick Commands to Run Tests for Open-Notebook

Execute these commands from the repository root to control test scope and output:

- **Run the entire test suite**: `uv run pytest`
- **Run a single test file**: `uv run pytest tests/test_models_api.py`
- **Run a specific test function**: `uv run pytest tests/test_models_api.py::test_create_notebook`
- **Run only unit tests**: `uv run pytest tests/unit/`
- **Generate coverage report**: `uv run pytest --cov=open_notebook`
- **Verbose output**: `uv run pytest -v`
- **Show printed output**: `uv run pytest -s`

The `uv run` prefix ensures the command executes within the project's virtual environment, isolating dependencies from your system Python.

## Test Suite Architecture

The `tests/` directory is organized into four distinct layers to separate concerns and execution speeds.

### Unit Tests (`tests/unit/`)

These validate pure business-logic functions without external dependencies. They cover domain model validation in `open_notebook/domain/`, repository helpers, and utility functions. Unit tests execute quickly and require no database connection.

### Integration Tests (`tests/integration/`)

Integration tests spin up the full FastAPI application (via `httpx.AsyncClient`) and a real SurrealDB instance to verify end-to-end flows. For example, a test might create a notebook, attach a source, and verify the persistence layer in a single async flow.

### API Tests (`tests/api/`)

These directly target the FastAPI routers defined in `api/routers/*.py`. They assert HTTP status codes, validate JSON response payloads, and check error handling logic without mocking the underlying services.

### Database Tests (`tests/database/`)

Focused on SurrealDB queries, migrations, and vector-search functionality, these tests ensure the persistence layer behaves correctly under concurrent async operations.

## Working with Async Test Patterns

Since open-notebook is built on async/await patterns, every test file must use the `@pytest.mark.asyncio` decorator and `await` all async calls. As seen in [`tests/test_models_api.py`](https://github.com/lfnovo/open-notebook/blob/main/tests/test_models_api.py) (lines 18-20), this mirrors the production code's async design.

Example of a complete async API test:

```python

# tests/api/test_notebooks_api.py

import pytest
from httpx import AsyncClient
from api.main import app  # FastAPI instance

@pytest.mark.asyncio
async def test_create_notebook_via_api():
    async with AsyncClient(app=app, base_url="http://test") as client:
        response = await client.post(
            "/api/notebooks",
            json={"name": "My Notebook", "description": "Demo"},
        )
        assert response.status_code == 200
        data = response.json()
        assert data["name"] == "My Notebook"

```

Run this specific test in isolation:

```bash
uv run pytest tests/api/test_notebooks_api.py::test_create_notebook_via_api -v

```

## Reusable Test Fixtures

The [`tests/conftest.py`](https://github.com/lfnovo/open-notebook/blob/main/tests/conftest.py) file defines shared fixtures that provide a clean async environment for every test. These fixtures handle temporary data population and automatic cleanup after each test run.

Example fixture for creating a temporary notebook:

```python

# tests/conftest.py

import pytest
from open_notebook.domain.notebook import Notebook

@pytest.fixture
async def test_notebook():
    nb = Notebook(name="Temp Notebook", description="Temp")
    await nb.save()
    yield nb
    await nb.delete()

```

Any test function can now use `await test_notebook` to receive a fresh notebook instance without manual setup or teardown boilerplate.

## Coverage Goals and Quality Gates

According to the official testing guide in [`docs/7-DEVELOPMENT/testing.md`](https://github.com/lfnovo/open-notebook/blob/main/docs/7-DEVELOPMENT/testing.md), the project maintains strict coverage thresholds:

- **70%+** overall code coverage
- **90%+** coverage for critical business logic in the domain layer

Generate a coverage report to verify these metrics locally:

```bash
uv run pytest --cov=open_notebook --cov-report=html

```

This creates an HTML report showing which lines in `open_notebook/domain/` and other modules lack test coverage.

## Summary

Running tests for open-notebook requires pytest with async support via `pytest-asyncio`.

- Execute `uv run pytest` from the repository root to run the full suite against Python 3.11+.
- Target specific layers using path arguments like `tests/unit/` or `tests/api/`.
- Leverage fixtures in [`tests/conftest.py`](https://github.com/lfnovo/open-notebook/blob/main/tests/conftest.py) for clean async setup and teardown.
- Use `@pytest.mark.asyncio` decorators on all test functions that call async code.
- Aim for 70%+ coverage, with 90%+ for domain logic, using the `--cov=open_notebook` flag.

## Frequently Asked Questions

### What testing framework does open-notebook use?

Open-notebook uses **pytest** as the core runner with the **pytest-asyncio** plugin to handle async/await patterns. The configuration is defined in [`pyproject.toml`](https://github.com/lfnovo/open-notebook/blob/main/pyproject.toml), specifying `asyncio_mode = auto` to simplify test decoration.

### How do I run tests without installing dependencies globally?

Use `uv run pytest` instead of `pytest` directly. The `uv` tool manages the virtual environment defined in [`pyproject.toml`](https://github.com/lfnovo/open-notebook/blob/main/pyproject.toml), ensuring all dev dependencies (including `pytest-asyncio` and `httpx`) are available without polluting your system Python.

### Why do my tests fail with "async fixture" errors?

All async fixtures and test functions must use the `@pytest.mark.asyncio` decorator. Additionally, ensure you are using the `async with` pattern for clients (like `httpx.AsyncClient`) and awaiting all database calls, as demonstrated in [`tests/conftest.py`](https://github.com/lfnovo/open-notebook/blob/main/tests/conftest.py) and the API test examples.

### Can I run tests against a real database?

Yes, the integration and database test layers in `tests/integration/` and `tests/database/` automatically spin up a SurrealDB instance. Ensure your environment has Docker available or a running SurrealDB server configured in your test environment variables before executing these specific test modules.