mitgliederverwaltung/docs/test-performance-optimization.md

5 KiB

Test Performance Optimization

Last Updated: 2026-01-28
Status: Implemented

This document records the test-suite performance work and — most importantly — the conventions that govern how tests are tagged and run. The seeds-test rationale in §1 is the canonical reference linked from test/seeds_test.exs.

Baseline result: the standard (fast) suite runs ~368 s (~6.1 min) vs. ~445 s before; the full suite (all tests) ~7.4 min. Slow-tagged tests (~25, >1 s each, ~77 s total) are excluded from standard runs and executed via promotion before merge.


1. Seeds Test Suite — coverage mapping

The seeds tests were reduced from 13 to 4. The 9 removed tests were dropped because their assertions are already covered by domain-specific test suites — this mapping is the justification and must be preserved:

Removed seeds test Covered by
"at least one member has no membership fee type assigned" membership_fees/*_test.exs
"each membership fee type has at least one member" membership_fees/*_test.exs
"members with fee types have cycles with various statuses" cycle_generator_test.exs
"creates all 5 authorization roles with correct permission sets" authorization/*_test.exs
"all roles have valid permission_set_names" authorization/permission_sets_test.exs
"does not change role of users who already have a role" merged into general idempotency test
"role creation is idempotent" (detailed) merged into general idempotency test

4 retained critical-bootstrap tests (and why)

These guard deployment-critical invariants that nothing else covers and must stay in the fast suite:

  1. Smoke test — seeds run successfully and create basic data.
  2. Idempotency — seeds can be re-run without duplicating data.
  3. Admin bootstrap — admin user exists with Admin role (critical for initial access).
  4. System-role bootstrapMitglied system role exists (critical for user registration).

If a new critical bootstrap requirement appears, add a test to the "Critical bootstrap invariants" section in test/seeds_test.exs. Removed-test risk is low: a smoke-test failure surfaces broken seeds, and domain tests verify business logic independently of seeds content.


2. Tagging convention: :slow

Tests are split into fast (standard CI) and slow (run via promotion before merge). A test is tagged @tag :slow when all of:

  • execution time > 1 s, and
  • low risk — does not catch critical regressions in core business logic, and
  • it is a UI/display/formatting test, a workflow-detail test, or an edge case with a large dataset (performance tests with 50+ records always qualify).

Never tag as :slow:

  • Core CRUD (Member/User create/update/destroy)
  • Basic authentication/authorization
  • Critical bootstrap (admin user, system roles)
  • Email synchronization
  • Representative policy tests (one per permission set + action)
  • A test that is merely slow due to inefficient setup or a bug — fix the setup/bug instead
  • An integration test — use @tag :integration instead

Use @describetag :slow (not @moduletag) for describe blocks, so unrelated tests in the same module are not tagged.

One-off isolation fix worth noting as a pattern: a test that loaded all members was slow in full runs because of cross-test data accumulation; constraining it with a search query (/members?query=Alice) made it both faster and properly isolated. Prefer query filters over loading all records.


3. Execution model

Mode Command Contents Time
Fast (default) just test-fast / mix test --exclude slow --exclude ui everything except :slow and :ui ~6 min
Slow only just test-slow / mix test --only slow the ~25 :slow tests ~1.3 min
Full just test / mix test all tests ~7.4 min

CI: standard pipeline (check-fast) runs mix test --exclude slow --exclude ui. The full suite (check-full) is triggered by promoting a Drone build to production and is required before merging to main (branch protection).

To find the slowest tests, run mix test --slowest N ad hoc. test/test_helper.exs also carries a slowest: 10 option for ExUnit.start/1, but it is commented out by default — uncomment it to print the 10 slowest tests at the end of every run.


4. Test organization

Tests mirror the lib/ structure:

test/
├── accounts/              # Accounts domain
├── membership/            # Membership domain
├── membership_fees/       # Membership fees domain
├── mv/                    # Core (accounts, membership, authorization)
├── mv_web/                # Web layer (controllers, live, components)
└── support/               # conn_case.ex, data_case.ex

References

  • Testing Standards: CODE_GUIDELINES.md §4
  • CI/CD: .drone.jsonnet
  • Test helper: test/test_helper.exs
  • Just commands: Justfile (test-fast, test-slow, test)