Skip to main content

A lightweight Python unit testing framework with decorator-based test collection and execution.

Project description

PyForge Testing Framework

A lightweight Python testing framework with decorator-based test collection and automatic discovery—designed for personal projects and learning.

PyPI version Python 3.12+ License: MIT Code Quality Type Checked

Note: PyForge is designed for personal projects, learning, and small-scale testing. It is not a substitute for production frameworks like pytest.

Features

  • 🎯 Simple Decorators — Mark tests with @test, automatic collection
  • 🚀 Zero Configuration — Works out of the box
  • 📦 Zero Dependencies — Pure Python, nothing to install but PyForge itself
  • 🔍 Auto-Discovery — Finds and loads all test*.py files automatically
  • Fast Execution — Minimal overhead, quick feedback
  • 🏷️ Test Markers — Organize tests by priority (integration, slow)
  • 📊 Parameterized Tests — Run one test with multiple inputs
  • Skip Tests — Conditionally skip tests with clear reasons
  • Full Type Hints — PEP 484 type annotations throughout
  • 🎨 Clean Output — Color-coded results with minimal internal noise

Installation

pip install pyforge-test

Or from GitHub:

pip install git+https://github.com/ertanturk/pyforge-test.git

Quick Start

1. Create Test File

mkdir -p tests && touch tests/__init__.py

Create tests/test_example.py:

from pyforge_test import test


@test
def test_addition() -> None:
    """Test basic arithmetic."""
    assert 2 + 2 == 4


@test
def test_strings() -> None:
    """Test string manipulation."""
    assert "hello".upper() == "HELLO"

2. Run Tests

pyforge

Expected output:

Discovering test modules in '/path/to/tests'...
Loaded: test_example.py

Loaded 1 test module(s).

Executing 2 test(s).

PyForge Test Results
------------------------------------------------------------------------

test_example.py
  PASSED test_addition (Line 4)
  PASSED test_strings (Line 9)

------------------------------------------------------------------------
Summary: PASSED: 2/2  FAILED: 0/2  SKIPPED: 0/2  ERRORS: 0/2
Took 5 ms to execute all tests
------------------------------------------------------------------------

CLI Options

pyforge              # Run all tests
pyforge -q           # Quiet: only failures
pyforge -v           # Verbose: full tracebacks
pyforge --fail-fast  # Stop on first failure
pyforge -k api       # Filter by test name
pyforge test_api.py  # Run specific file

Test Features

Basic Tests

from pyforge_test import test


@test
def test_example() -> None:
    """Test function requirements:
    - Starts with 'test_'
    - No parameters
    - Return type -> None
    - Uses @test decorator
    """
    assert True

Parameterized Tests

Run the same test with multiple inputs:

from pyforge_test import test_parameterized


@test_parameterized([
    (2, 3, 5),
    (10, 5, 15),
    (100, 200, 300),
])
def test_addition(a: int, b: int, expected: int) -> None:
    """Generates: test_addition_0, test_addition_1, test_addition_2"""
    assert a + b == expected

Test Markers

Execution priority: Unmarked (0)Integration (1)Slow (2)

from pyforge_test import test, test_marker

# Fast unit test (runs first)
@test
def test_fast() -> None:
    assert 2 + 2 == 4

# Integration test (requires external resources)
@test_marker("integration")
@test
def test_database() -> None:
    db.connect()
    assert db.is_connected()

# Slow test (performance-intensive)
@test_marker("slow")
@test
def test_large_dataset() -> None:
    result = process_records(1_000_000)
    assert len(result) == 1_000_000

Important: @test_marker must come before @test

Skip Tests

import sys
from pyforge_test import test, test_skip, test_skipif


@test_skip(reason="Not implemented yet")
def test_future() -> None:
    """Always skipped."""
    pass


@test_skipif(sys.platform == "win32", reason="Unix only")
def test_unix() -> None:
    """Skipped on Windows."""
    pass

Project Structure

my-project/
├── src/
│   ├── main.py
│   └── utils.py
├── tests/
│   ├── __init__.py            # Required (can be empty)
│   ├── test_main.py           # Auto-discovered
│   └── test_utils.py          # Auto-discovered
├── README.md
└── pyproject.toml

Code Quality

PyForge is fully type-checked and linted:

  • Ruff: All checks passing ✅
  • Pylint: 9.89/10 score ✅
  • Pyright: Strict type checking ✅
  • Type Hints: Full PEP 484 compliance ✅

Documentation

Development

Code standards:

  • PEP 484 type hints on all functions
  • Google-style docstrings
  • Exception chaining: raise ... from e
  • No bare except statements

License

MIT — See LICENSE

Contributing

Contributions welcome! Open an issue or PR on GitHub.


Status: Alpha (v0.2.0) | Python: 3.12+ | Type Safe: Yes | Dependencies: 0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyforge_test-0.3.0.tar.gz (23.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyforge_test-0.3.0-py3-none-any.whl (18.2 kB view details)

Uploaded Python 3

File details

Details for the file pyforge_test-0.3.0.tar.gz.

File metadata

  • Download URL: pyforge_test-0.3.0.tar.gz
  • Upload date:
  • Size: 23.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyforge_test-0.3.0.tar.gz
Algorithm Hash digest
SHA256 5d265406cd31b404ce1645f2ab8d7fb181639969360d6b39d04bfb5ee3984e0e
MD5 1218fff6fdca55d229a28e0a13824771
BLAKE2b-256 4ec8bb33e8c9a36c8fa9d1b6f277b7d64eec03c23c12981c2c4831e77e4eb9fe

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyforge_test-0.3.0.tar.gz:

Publisher: publish.yml on ertanturk/pyforge-test

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyforge_test-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: pyforge_test-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 18.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyforge_test-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4ec34777016e7ffe8b234c9931d0567bafaede406f897be9af4ac8089eae0b7e
MD5 0f0cba1796148f64bf55a606399db55a
BLAKE2b-256 2bbe4b1b5624953a417df1948240c1b53ff9600fe48c35cb63a769e98f9506cc

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyforge_test-0.3.0-py3-none-any.whl:

Publisher: publish.yml on ertanturk/pyforge-test

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page