Tutorial 1 — Your first Markdown test

In this tutorial you will install markdown-pytest, write a Python code block in a Markdown file, mark it as a test with an HTML comment, and run it with pytest. The whole thing takes about five minutes.

Prerequisites

  • Python 3.10 or newer

  • pip available in your shell

No prior pytest knowledge is required, although it helps to know what a test function looks like.

Step 1 — Install

pip install markdown-pytest

That is all you need. The package registers itself as a pytest plugin via the pytest11 entry point, so pytest discovers it automatically — no conftest.py or pytest_plugins declaration is needed.

To verify the installation:

pytest --co -q README.md   # --co = collect only, -q = quiet

If markdown-pytest is installed and the file contains marked blocks, you will see the test names listed. If the file has no marked blocks yet, the output is empty — that is fine.

Step 2 — Create a Markdown file

Create a file called guide.md in the root of your project (or open an existing one).

The file can be anything — a README, a tutorial, API documentation, a changelog. markdown-pytest ignores all content it does not recognise, so you can add tests incrementally to files that already exist.

Step 3 — Write a code block and mark it as a test

Paste the following into guide.md:

# My library

Here is a quick example:

<!-- name: test_addition -->
```python
result = 1 + 1
assert result == 2
```

The <!-- name: test_addition --> comment is the only thing markdown-pytest needs. It tells the plugin:

  • this block exists (not ignored)

  • the test is named test_addition

The comment is invisible in rendered HTML — GitHub, MkDocs, Sphinx, and every other Markdown renderer hide HTML comments from readers.

Naming rules

The name must start with test by default (configurable, see Configuration reference). It follows the same conventions as a Python function name: letters, digits, and underscores.

Valid names

test_addition, test_parses_csv, test_edge_case_empty_list

Invalid names — these are silently ignored

addition (no test prefix), test addition (space), Test_Addition (uppercase T — treated as a different prefix)

Step 4 — Run the test

pytest guide.md

Expected output:

========================= test session starts ==========================
collected 1 item

guide.md::test_addition PASSED                                   [100%]

========================== 1 passed in 0.01s ===========================

Add -v for the verbose form that shows each test name on its own line:

pytest -v guide.md
========================= test session starts ==========================
collected 1 item

guide.md::test_addition PASSED                                   [100%]

========================== 1 passed in 0.01s ===========================

Step 5 — Make the test fail

Understanding failure output is as important as knowing how to pass. Change the assertion:

<!-- name: test_addition -->
```python
result = 1 + 1
assert result == 3   # wrong on purpose
```

Run again:

pytest guide.md
========================= test session starts ==========================
collected 1 item

guide.md::test_addition FAILED                                   [100%]

================================ FAILURES ==============================
_______________________ test_addition __________________________

guide.md:7: AssertionError

======================= short test summary info ========================
FAILED guide.md::test_addition - AssertionError
========================= 1 failed in 0.01s ============================

The traceback points directly to the line in guide.md — not to some generated temp file. Fix the assertion back to == 2 before continuing.

Step 6 — Run all Markdown files at once

If your project has multiple Markdown files, point pytest at a directory:

pytest docs/

Or mix Markdown with regular Python test files:

pytest docs/ tests/

pytest collects .md and .markdown files automatically. Files without any marked blocks are silently skipped.

Step 7 — Add to CI

In GitHub Actions, add a step like:

- name: Test documentation examples
  run: pytest -v README.md docs/

Or extend an existing test step to include Markdown files alongside tests/:

- name: Run tests
  run: pytest -v tests/ README.md

What you learned

  • Install markdown-pytest with a single pip install.

  • Mark a Python code block by placing <!-- name: test_... --> directly above it.

  • Run pytest <file>.md to execute the tests.

  • Tracebacks reference the original Markdown line numbers.

Next steps

A single block per test works well for short self-contained examples. For longer examples with explanatory prose in between, see Tutorial 2 — Splitting a test across multiple blocks — it shows how to spread one test across several code blocks.