Tutorials / Framework Features
Metadata and targeting
Every @test can carry structured metadata — owner, component, tags, priority. That metadata is more than documentation: pass any of those attributes back to the runner and it becomes a filter, letting you run exactly the subset you need without touching the test code.
Annotating tests
Attach metadata directly on the decorator:
@Suite(owner="checkout-team") class CheckoutSuite: @test( owner="checkout-team", component="payment", tags=["smoke", "regression"], priority=1, ) def test_card_payment(self): ... @test( owner="checkout-team", component="cart", tags=["regression"], priority=2, ) def test_add_to_cart(self): ...
owner=, it inherits the suite's owner=. Set it on @Suite as a default and override only on the tests that have a different owner.Execution priority
priority= controls the order tests (and suites) run in — it is not a filter. Tests with a lower number run before tests with a higher number. Tests with no priority set run after all prioritized tests.
The full execution order within a run is:
@Suite() class CheckoutSuite: @test(priority=1) # runs first def test_login(self): ... @test(priority=2) # runs second def test_add_to_cart(self): ... @test(parallel=True) # no priority — runs after prioritized tests def test_search(self): ... @test() # no priority, not parallel — runs last def test_logout(self): ...
priority= set — run first, ascending order (1 before 2 before 3).2. Tests with no priority but
parallelized=True — run next.3. Tests with no priority and
parallelized=False — run last.@Suite also accepts priority= with the same rules, ordering suites relative to each other.Targeting at runtime
Pass the same attributes to runner.run() to filter which tests execute. Tests that don't match are skipped, not removed:
from test_junkie.runner import Runner runner = Runner([CheckoutSuite, LoginSuite, SearchSuite]) # CI smoke pass: priority 1 smoke-tagged tests only runner.run( components=["payment", "cart"], tag_config={"run_on_match_any": ["smoke"]}, ) # triage: run only what the checkout team owns runner.run(owners=["checkout-team"]) # nightly: full regression, no filter runner.run()
Tag filtering options
tag_config supports four modes — any combination can be set at once:
runner.run(
tag_config={
# run if ANY of these tags match
"run_on_match_any": ["smoke", "critical"],
# run only if ALL of these tags match
"run_on_match_all": ["regression", "payment"],
# skip if ANY of these tags match
"skip_on_match_any": ["wip"],
# skip only if ALL of these tags match
"skip_on_match_all": ["slow", "flaky"],
}
)
Runtime metadata: Meta.update()
Static metadata on the decorator is useful for targeting. For values only known at run time — build IDs, dynamic results, environment state — use Meta.update() inside the test.
Non-parametrized test
When the test has no parameters, call Meta.update(self, ...) with just the keyword values you want to attach:
from test_junkie.meta import Meta @Suite() class CheckoutSuite: @test(owner="checkout-team", component="payment") def test_card_payment(self): order = checkout(card="4111111111111111") Meta.update(self, order_id=order["id"], amount=order["total"]) assert order["status"] == "confirmed"
Parametrized test
When the test has parameters, you must also pass parameter= and/or suite_parameter= to Meta.update(). These tell it which variant's metadata record to write to — without them, the update targets the None entry, which doesn't exist for a parametrized test and the update is silently lost:
@Suite(parameters=[ {"env": "staging"}, {"env": "prod"}, ]) class CheckoutSuite: @test( owner="checkout-team", parameters=[{"card": "visa"}, {"card": "amex"}], ) def test_card_payment(self, parameter, suite_parameter): order = checkout( card=parameter["card"], env=suite_parameter["env"], ) # pass both parameter and suite_parameter so Meta.update # writes to the correct variant record (e.g. prod/amex) Meta.update( self, parameter=parameter, suite_parameter=suite_parameter, order_id=order["id"], amount=order["total"], ) assert order["status"] == "confirmed"
parameter=), pass only suite_parameter=suite_parameter. If it only has test-level parameters, pass only parameter=parameter. Pass both when the test declares both.The attached values appear in the test's metadata record, accessible via test_obj.metrics.get_metrics() after the run.