Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 40 additions & 7 deletions docs/04_pytest.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ Inside those files, test functions usually start with `test_`.
Example:

```python
def test_count_words_returns_zero_for_empty_text() -> None:
result = count_words("")
def test_count_characters_includes_whitespace_by_default() -> None:
result = count_characters("hello world")

assert result == 0
assert result == 11
```

The function name describes the expected behavior.
Expand All @@ -108,15 +108,48 @@ This means:
Example:

```python
def test_normalize_whitespace_replaces_repeated_spaces() -> None:
text = "Python is fun"
def test_count_characters_can_ignore_whitespace() -> None:
result = count_characters("hello world", include_whitespace=False)

assert result == 10
```

This style makes tests easier to read and review.

## Parametrizing related cases

Sometimes several inputs should follow the same behavior. Copying the entire
test for each input would make the test file repetitive.

pytest can run one test function with several sets of values:

```python
import pytest


@pytest.mark.parametrize(
("text", "expected"),
[
("Python is fun", "Python is fun"),
("Python\tis\nfun", "Python is fun"),
(" \t\n ", ""),
(" Python project ", "Python project"),
],
)
def test_normalize_whitespace_handles_common_inputs(text: str, expected: str) -> None:
result = normalize_whitespace(text)

assert result == "Python is fun"
assert result == expected
```

This style makes tests easier to read and review.
The names `text` and `expected` match the two values in every tuple. pytest
runs the function once for each tuple and reports every case separately.

This example covers repeated spaces, tabs and newlines, whitespace-only text,
and leading or trailing spaces without duplicating the test logic.

Parametrization is useful when the action and assertion stay the same. Use
separate tests when cases describe different behavior or need different setup.

## pytest configuration

Expand Down
2 changes: 2 additions & 0 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ These parts are already included in the repository.
- [x] Explain linting and formatting
- [x] Explain when ignoring linting rules may be reasonable
- [x] Check internal Markdown links with pytest
- [x] Add whitespace edge cases to the example test suite
- [x] Demonstrate pytest parametrization with related inputs

### Continuous integration

Expand Down
46 changes: 24 additions & 22 deletions tests/test_text_stats.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,42 @@
"""Tests for basic text statistics utilities."""

import pytest

from text_toolkit import (
count_characters,
count_words,
normalize_whitespace,
)


def test_normalize_whitespace_replaces_repeated_spaces() -> None:
text = "Python is fun"

result = normalize_whitespace(text)

assert result == "Python is fun"


def test_normalize_whitespace_handles_tabs_and_newlines() -> None:
text = "Python\tis\nfun"

@pytest.mark.parametrize(
("text", "expected"),
[
("Python is fun", "Python is fun"),
("Python\tis\nfun", "Python is fun"),
(" \t\n ", ""),
(" Python project ", "Python project"),
],
)
def test_normalize_whitespace_handles_common_inputs(text: str, expected: str) -> None:
result = normalize_whitespace(text)

assert result == "Python is fun"


def test_count_words_returns_zero_for_empty_text() -> None:
result = count_words("")
assert result == expected

assert result == 0


def test_count_words_handles_repeated_whitespace() -> None:
text = "Python project\nworkflow"

@pytest.mark.parametrize(
("text", "expected"),
[
("", 0),
(" \t\n ", 0),
(" Python project ", 2),
("Python project\nworkflow", 3),
],
)
def test_count_words_handles_common_whitespace(text: str, expected: int) -> None:
result = count_words(text)

assert result == 3
assert result == expected


def test_count_characters_includes_whitespace_by_default() -> None:
Expand Down
Loading