01.02 — ISTQB vs pytest / Jest / Mocha#

The methodological observation#

Past the technical bet on the technical / non-technical barrier (see 01-flip-the-problem.md), there’s a second bet: the one on trade vocabulary.

The ISTQB and professional testers have spent decades building a precise, battle-tested vocabulary: test cycles, campaigns, test suites, test cases, test steps. A clear hierarchy, built to organize, trace and drive software quality.

Automation tools have largely ignored that legacy.

pytest, Jest, Mocha… they’re all hybrid mixes where testers have to learn to think like developers, and nobody really speaks the same language.

The architectural consequence#

Ocarina takes that vocabulary seriously and ports it straight into the class hierarchy.

ISTQB vocabularyOcarina classSource file
Test stepact() (user verb, returns ActionStart[TPOM])src/ocarina/dsl/testing_with_railway/constructors/create_act.py
Test caseTest[Driver]src/ocarina/dsl/testing/oc_test.py
Test suiteTestSuite[Driver]src/ocarina/dsl/testing/oc_test_suite.py
CampaignTestCampaign[Driver]src/ocarina/dsl/testing/oc_test_campaign.py
CycleTestCycle[Driver]src/ocarina/dsl/testing/oc_test_cycle.py

Not “decorative namespaces”. Every level has a distinct job (see ../02-ocarina/05-orchestration/):

LevelJob
actOne atomic action on a page.
TestMetadata (name, test_id, skipped) + scenario + pre/post fragments + watchers.
TestSuiteDriver pool, parallelization, saturation, ID filtering, retry policy.
TestCampaignSequence of suites with shared workers config.
TestCycleSmoke + main, mode applies to the smoke tests (fail-fast | wait-for-all).

The break with pytest#

Ocarina is not a pytest plugin. The README says so flat out:

Ships its own test runner: Ocarina is NOT a pytest plugin.

Why?

  1. pytest vocabulary isn’t ISTQB. pytest has test_function, parametrize, fixture, conftest. Internally coherent, but a different universe. Wrapping Ocarina as a pytest plugin would have forced translation — exactly what the philosophy refuses (see 01-flip-the-problem.md).
  2. Independence. A plugin depends on its host’s API. Ocarina wants to be auditable in an afternoon, no pytest knowledge required.
  3. Stance on fixtures. Ocarina swaps fixtures for closures + scenario fragments + Effect for setup/teardown. Stance: “poor man’s rich” — one mechanism, the closure, for every injection. One closure does what classical OO would pull off with fixtures + scopes + inheritance.

The break with Cucumber / Gherkin#

No .feature file, no step definition, no glue layer. The scenario is Python, directly executable, directly typed, directly refactorable. No permanent translation to maintain.

The “language” Ocarina exposes to scenarios isn’t a text DSL. It’s an embedded Python DSL:

return [
    drive_page(
        act(on_homepage, open_then_verify_homepage)
            .failure(just_log_error("Failed to reach the homepage..."))
            .success(log_success_with_current_url_and_take_screenshot("On the homepage!")),
        act(on_homepage, click_book_call_page_cta)
            .failure(just_log_error("Failed to click on the 'Book a call' CTA..."))
            .success(just_log_success("Clicked on the 'Book a call' CTA!")),
    ),
    drive_page(
        act(on_book_a_call_page, verify_book_call_page)
            .failure(just_log_error("Failed to verify the 'Book a call' page..."))
            .success(log_success_with_current_url_and_take_screenshot("On the 'Book a call' page!")),
    ),
]

Pure Python. No lexer, no third-party runtime, no translation. Typed too — the slightest mismatch is a mypy error (see ../02-ocarina/03-railway/02-action-chain-states.md).

Consequence on reporting#

The reporting sticks to ISTQB vocabulary too. pretty_print_results spits out:

Campaign
• Suite
  > Test case 1
    » PASSED
  > Test case 2
    » FAILED
      → Error message
        ⫸ At step 3

Three indents, three levels: campaign, suite, case. The step only shows up as failure context (“At step 3”). No Python class name surfaces in the output — the end user sees trade vocabulary, not code.

ISTQB ↔ Ocarina glossary#

ISTQB termOcarina termNote
Test stepact()Atomic action.
Test caseTest[Driver]Wraps a scenario.
Test scenarioScenario[Driver]Made of a test_chain, a setup, a teardown, watchers.
Test suiteTestSuite[Driver]Parallelized.
Test campaignTestCampaign[Driver]Sequential (between suites).
Test cycleTestCycle[Driver]Smoke + main, fail-fast or wait-for-all.
Smoke testsmoke_tests_campaigns=Gate.
SetupScenario.setup: EffectEffect.
TeardownScenario.teardown: EffectEffect too. Always runs, errors swallowed.
Test reportpretty_print_results, generate_docx_proof, generate_json_resultsPost-execution plugins.

The Holy Book draws a sharp dependency: this vocabulary couldn’t have been embodied this rigorously before PEP 695 generics, because you need to parameterize TestSuite[Driver] with a precise driver type. From the Holy Book (chapter “First feedbacks”):

The recent evolution of Python’s type system is central to what makes Ocarina possible. Without being “the future” either: this is established science, but one that arrived cruelly late in our ecosystem.

That’s why the framework requires requires-python = ">=3.14" (see ../00-big-picture/02-stack-matrix.md).