Tutorials / CI and the command line

Random order and --seed

Tests that only pass in a certain order hide real bugs: shared state, leftover data, a cache that one test warms for the next. Shuffling the order finds them; the seed lets you repeat the order that failed.

An order-dependent test

TestOrder.RANDOM shuffles the tests of a suite on every run:

cart_suite.pypython
from test_junkie.constants import TestOrder
from test_junkie.decorators import Suite, beforeClass, test


@Suite(order=TestOrder.RANDOM)
class CartSuite:

    @beforeClass()
    def setup(self):
        self.cart = Cart()

    @test()
    def add_item(self):
        self.cart.add("book")
        assert len(self.cart) == 1

    @test()
    def checkout_total(self):
        # passes only when add_item ran first - the hidden dependency
        assert self.cart.total() == 12.99

In declaration order this suite always passes. Shuffled, checkout_total fails whenever it runs first.

The header prints the seed

Every run with a shuffled suite prints the seed that produced its order:

tj runoutput
Test Junkie 0.9a6 · Python 3.12.5 · Linux
  tests    tests · 1 suite, 2 tests · found in 0.01s
  mode     sequential
  order    random · seed 583207  repeat this order with --seed 583207

Repeat the order that failed

Pass the seed back and the tests run in exactly the same order, so the failure happens again while you fix it:

terminalbash
tj run --seed 583207

From Python, give the runner the seed:

run.pypython
from test_junkie.runner import Runner

Runner([CartSuite], seed=583207).run()
Same seed, same order
The seed fixes the order of every shuffled suite in the run. Filtering with -t or tags keeps the remaining tests in the same relative order, so you can narrow a failure down to the two tests involved.

Fix the dependency, not the order

Once you can repeat it, give each test what it needs instead of relying on another test:

cart_suite.pypython
@Suite(order=TestOrder.RANDOM)
class CartSuite:

    @beforeTest()
    def fresh_cart(self):
        self.cart = Cart()  # every test starts from an empty cart

    @test()
    def add_item(self):
        self.cart.add("book")
        assert len(self.cart) == 1

    @test()
    def checkout_total(self):
        self.cart.add("book")
        assert self.cart.total() == 12.99
Shuffle in CI, not just locally
A suite that runs in the same order every time can't tell you it has hidden dependencies. Keeping TestOrder.RANDOM on suites in CI finds them early, and the seed in the log makes any failure repeatable.