Skip to main content
Case is a container for a single scenario: inputs you will pass to your System Under Test (SUT), plus optional reference values you’ll assert against. Using Case enables:
  • Iterating one merit function over many scenarios with @merit.iter_cases(...)
  • Grouping related cases with CaseGroup and iterating with @merit.iter_case_groups(...)
  • Keeping inputs in sut_input_values (to call sut(**case.sut_input_values))
  • Storing reference data in references (typed or untyped)
  • Tagging and filtering with tags, and attaching context with metadata

Basic Usage

Case API

Adding input values

sut_input_values is a dictionary of keyword arguments that will be passed to your SUT:

Typed references

Use Case[YourModel] to get IDE autocomplete and runtime validation of references.

Untyped references

The default Case uses untyped references (a dict) and references defaults to {}:

Providing ID for persistence

Each case has an id: UUID (auto-generated by default). Provide it explicitly when you want stable case IDs across runs or when you store cases in datasets. This matters because @merit.iter_cases(...) uses case.id to build readable, stable parametrization IDs.

Adding metadata

Use metadata for extra context and reporting. Values must be JSON-like primitives (str | int | float | bool | None).

Adding tags for filtering

Use tags to label cases and then select subsets with normal Python:

Validating cases for a SUT

If cases come from files/APIs, validate them against your SUT’s signature by attaching them to @merit.sut(validate_cases=...):

CaseGroup

A CaseGroup bundles related Case objects together with group-level references and a pass threshold (min_passes). This is useful when your evaluation naturally splits into logical groups (e.g. topics, languages, difficulty tiers) and you want to:
  • Assert on group-level data that applies to every case in the group
  • Set a per-group pass threshold instead of a single global one
  • Get hierarchical reporting: run → groups → cases

Basic Usage

@merit.iter_case_groups injects two parameters by name:
  • group — the current CaseGroup (with its name, references, and cases)
  • case — the current Case inside that group
The merit passes only if every group meets its own min_passes threshold.

Typed group references

Just like Case[RefsT], CaseGroup accepts two type parameters: one for case-level references and one for group-level references.

Validation

CaseGroup enforces these constraints at creation time:
  • cases must contain at least 1 case
  • min_passes must be ≥ 1
  • min_passes cannot exceed the number of cases

Validating grouped cases for a SUT

To validate all case inputs against your SUT signature, flatten the groups:

Recommendations

1. Use Cases when data comes from external sources

If you’re hardcoding inputs directly in your merit functions, you probably don’t need Case. Don’t do this:
Do this:
When loading cases from JSON/APIs, prefer Case[YourModel] (typed references) and validate inputs up-front with @merit.sut(validate_cases=...).

2. Use tags and metadata for dynamic case selection

Structure your cases with tags and metadata to enable flexible selection without changing merit code.