test_* functions, Merit discovers and runs merit_* functions - each one checking how well your AI system performs using Merit’s APIs and components.
Basic Usage
The simplest merit function is a function whose name starts withmerit_. Merit automatically discovers and executes these functions.
merit_* functions, executes them, and generates a report - just like pytest but for AI system evaluation.
Merit Discovery
Merit follows pytest’s discovery patterns, finding merits in files, functions, and classes that follow naming conventions.Files
Merit discovers Python files starting withmerit_:
project
merit_chatbot.py ✓ Discovered
merit_agent.py ✓ Discovered
tests
merit_rag.py ✓ Discovered
helpers.py ✗ Not discovered
src
agent.py ✗ Not discovered
Functions
Within discovered files, Merit collects functions starting withmerit_:
Classes
Classes starting withMerit are discovered, and their merit_* methods become merit cases:
Dependency Injection
Merit automatically injects dependencies by matching parameter names to registered resources, SUTs, and metrics.Async Support
Merit automatically detects and runs async functions:asyncio.run() needed.
Iterate Merits
AI systems are inherently non-deterministic, making it essential to test them across multiple scenarios and runs. Merit provides three distinct approaches to iterate the same merit definition, each optimized for different use cases: quick parametrization for a few variations, structured cases for large datasets, and repeated execution to assess consistency.Iterate with different parameters
When you need to run the same merit with a small set of different inputs,@merit.parametrize offers the most concise syntax. It’s ideal for testing a handful of variations without the overhead of defining structured case objects.
merit_geography_bot(city='Boston', state='Massachusetts')merit_geography_bot(city='Austin', state='Texas')
Iterate with different cases
When evaluating against tens or hundreds of examples, or when you need consistent typing and structure, use@merit.iter_cases with Case objects. This approach provides type safety through Pydantic validation and enables loading test cases from external sources like JSON files or databases.
min_passes on iter_cases works like repeat: by default all case executions must pass, but you can require a lower threshold when evaluating large or noisy datasets.
Iterate with grouped cases
When your cases naturally fall into groups (e.g. topics, difficulty tiers, languages), use@merit.iter_case_groups with CaseGroup objects. Each group carries its own group-level references and a min_passes threshold, giving you hierarchical reporting (run → groups → cases) and per-group pass/fail semantics.
min_passes. Inside the merit function, group and case are injected automatically — use group.references for group-level data and case.references for case-level data.
Repeat with same data
AI systems can produce different outputs for identical inputs due to their non-deterministic nature. Use@merit.repeat to run the same merit multiple times with the same data, measuring consistency and reliability of your AI component.
Organizing Merits with Tags
Running only specific Merits
Use@merit.tag to organize and filter merits:
Skipping Merits unconditionally
Skip merits with@merit.tag.skip:
Skipping Merits conditionally
Expected Failures
Mark merits expected to fail with@merit.tag.xfail:
strict=True when the merit passing would be surprising and worth investigating.
Recommendations
1. Name functions descriptively
Merit function names become merit case identifiers in reports. Use descriptive names that explain what’s being evaluated. Don’t do this:2. Use dependency injection over global imports
Merit’s dependency injection system enables better resource management and merit isolation. Inject dependencies as parameters instead of importing globally. Don’t do this:- Automatic setup and teardown
- Resource scoping and reuse
- Merit isolation
- Better reporting and analytics
3. Organize related merits in Merit classes
Group related merits in classes for better organization and shared tags/setup: Don’t do this:- Logical grouping in reports
- Shared tags that cascade to methods
- Better code organization
- Easier navigation in IDEs