Skip to content

Lifecycle Hooks

Inside a @suite, functions annotated with lifecycle hooks prepare and clean up shared state without repeating code in each test.

Decorator When it runs
@before_all Once before the first test
@before_each Before each individual test
@after_each After each individual test
@after_all Once after the last test

The example below uses a shared map state to demonstrate that @before_each increments state.n once per test, @after_each records teardowns, and @before_all runs exactly once for the entire suite:

Runs via zolo test. The second test validates the counters accumulated by both hooks to prove execution order.

06-hooks.zolo
// Lifecycle hooks (T2): @before_each / @after_each / @before_all / @after_all.

//

// `before_each` runs before EACH test in the suite, so the shared counter

// `state.n` increments to 1 before `primeira` and to 2 before `segunda`.

@suite("contador")
mod hook_suite {
  let state = #{ "n": 0, "torn_down": 0, "setup_all": 0 }

  @before_all
  fn open() { state.setup_all = state.setup_all + 1 }

  @before_each
  fn inc() { state.n = state.n + 1 }

  @after_each
  fn teardown() { state.torn_down = state.torn_down + 1 }

  @test
  fn primeira() { expect(state.n).to_eq(1) }

  @test
  fn segunda() {
    // before_each ran twice; after_each ran once (after `primeira`);

    // before_all ran exactly once.

    expect(state.n).to_eq(2)
    expect(state.torn_down).to_eq(1)
    expect(state.setup_all).to_eq(1)
  }
}

Requires the Zolo CLI/host — open in the playground or run locally.

Hooks have access to the same variables declared in the @suite module scope, so state can be freely mutated between them and the tests.

enespt-br