TS004: TestNamingConvention

Overview

Property Value
ID TS004
Name TestNamingConvention
Group tests
Severity NOTE

Description

Verifies that test files follow naming conventions for automatic test discovery.

pytest discovers tests by looking for files matching specific patterns. If your test files don’t follow these conventions, they may be silently skipped during test runs.

What it checks

The check scans all Python files in tests/ or test/ directories and verifies they match pytest’s discovery patterns:

  • PASSED: All Python files match test_*.py or *_test.py pattern
  • FAILED: One or more files don’t match the expected patterns
  • NOT_APPLICABLE: No tests directory found

Default allowed patterns

  • test_*.py (recommended, e.g., test_module.py)
  • *_test.py (alternative, e.g., module_test.py)

Default allowed files

These files are allowed without matching the pattern:

  • __init__.py (package marker)
  • conftest.py (pytest fixtures)

How to fix

Rename test files to use proper prefix

# Before - pytest won't discover these
tests/
    my_tests.py          # Wrong: not "test_*" or "*_test"
    tests_for_module.py  # Wrong: not "test_*" or "*_test"

# After - pytest will discover these
tests/
    test_my_module.py    # Correct: starts with "test_"
    test_module.py       # Correct: starts with "test_"

Use suffix pattern if preferred

# Also valid pytest patterns
tests/
    module_test.py       # Correct: ends with "_test"
    integration_test.py  # Correct: ends with "_test"

Move helper modules to conftest or separate files

# Before - pytest tries to collect from helpers.py
tests/
    helpers.py           # Contains test utilities, not tests
    test_module.py

# After - clear separation
tests/
    conftest.py          # Move fixtures here (allowed by default)
    test_module.py

Or if you need shared utilities that aren’t fixtures:

tests/
    conftest.py
    test_module.py
    _helpers.py          # Private module (starts with _)

Configuration

Add custom patterns

If your project uses different naming conventions:

[tool.pycmdcheck.checks.TS004]
patterns = [
    "test_*.py",
    "*_test.py",
    "check_*.py",  # Custom pattern
]

Add allowed files

Allow additional support files without matching patterns:

[tool.pycmdcheck.checks.TS004]
allowed_files = [
    "fixtures.py",
    "helpers.py",
    "factories.py",
]

Skip this check

[tool.pycmdcheck]
skip = ["TS004"]

CLI

pycmdcheck --skip TS004

Why naming matters

Test discovery

pytest’s default test discovery:

# pytest.ini or pyproject.toml
[tool.pytest.ini_options]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]

Files not matching these patterns are ignored, which can lead to:

  • Tests silently not running
  • False confidence in test coverage
  • Confusion when tests “pass” but bugs remain

IDE integration

Most IDEs recognize test_*.py files for:

  • Test runner integration
  • Coverage highlighting
  • Quick navigation to tests

Convention over configuration

Using standard patterns means:

  • New contributors immediately understand the structure
  • CI/CD pipelines work without custom configuration
  • Tools like pytest-cov, tox, and nox work out of the box

References