Executable specifications, fixed development mocks, and lightweight checks—next to the Python function they describe.
日本語 README · Documentation · PyPI · License
niltest keeps representative behavior beside the implementation. One case can serve as readable documentation, a fixed mock in development, and a check against the real implementation. It supports Python 3.10+ on Windows, macOS, and Linux.
# Active virtual environment
pip install niltest
# Windows
python -m pip install niltest
# Ubuntu / macOS
python3 -m pip install niltestimport niltest
from niltest import Mode, expect, scenario
niltest.configure(mode=Mode.MOCK) # Set this before importing decorated modules.
@scenario("Shipping fee")
def shipping_fee(subtotal: int, premium: bool = False) -> int:
if expect:
expect.case(
"Premium members ship free",
given={"subtotal": 1_000, "premium": True},
returns=0,
)
return 0 if premium or subtotal >= 5_000 else 500
assert shipping_fee(1_000, premium=True) == 0
niltest.configure(mode=Mode.TEST)
assert niltest.run_tests(shipping_fee).successproduction is the safe default. It returns the original function without a niltest wrapper. Choose test to run cases against the implementation, or mock to return fixed values for matching cases.
from niltest import Mode, configure
configure(mode=Mode.TEST) # Recommended: completion and type checking
configure(mode="test") # Supported for compatibility and brevitySet a development mode before importing the module that contains @scenario. You can also set NILTEST_MODE=test or NILTEST_MODE=mock before starting Python.
returns accepts plain values, dataclass instances, types, Pydantic-backed conforms_to() expectations, and validator functions. Install niltest[pydantic] to validate and normalize typed case inputs with Pydantic.
from niltest import case, docs, scenario
@scenario("Withdraw funds")
@docs(case("insufficient funds", given={"balance": 100, "amount": 150}, raises=ValueError, match="insufficient"))
def withdraw(balance: int, amount: int) -> int:
if amount > balance:
raise ValueError("insufficient funds")
return balance - amountUse exactly one of returns or raises. Exception cases verify the real implementation and never act as mocks.
inspect imports a module and lists its registered scenarios; it does not execute cases. Replace your_package.services with an importable module path such as your_package/services.py.
niltest inspect your_package.services # terminal text
niltest inspect your_package.services --format json # CI and tools
niltest inspect your_package.services --format markdown # review documentsThe repository includes an inspectable example, its English Markdown report, and a Japanese annotated report. --json remains an alias for --format json.
niltest complements pytest rather than replacing it. With --niltest, each declared case is collected as an independent pytest item and participates in normal reports, JUnit XML, and coverage. Without the flag, the plugin is inert.
pytest --niltest --niltest-module=your_package.specs
pytest --niltest --junitxml=report.xml --cov=your_package[tool.pytest.ini_options]
niltest_modules = ["your_package.specs"]For declaration-style specifications outside a function body, use @docs. In production mode, @scenario returns the original function with no runtime wrapper or niltest branch.
from niltest import case, docs, scenario
@scenario("Shipping fee")
@docs(case("premium", given={"premium": True}, returns=0))
def shipping_fee(premium: bool) -> int:
return 0 if premium else 500Japanese and English are built in. niltest detects the operating-system locale and falls back to English. Add languages with register_locale() and the validated locale template.
PyPI distributions use Trusted Publishing and carry Sigstore attestations. GitHub Releases contain build-provenance attestations, and every distribution has SLSA Build Level 3 provenance.
gh attestation verify niltest-*.whl --repo disnana/niltest
gh attestation verify niltest-*.tar.gz --repo disnana/niltestCodex and GPT-5.6 supported repository audit, API design, implementation, test diagnosis, packaging, localization, and documentation. Changes were reviewed through executable tests and CI.
MIT © 2026 Disnana