How does EK9 enforce test quality at compile time?

← Testing · Ref: Q809

EK9 validates test quality during compilation. Tests that verify nothing or have unreachable assertions are compiler errors, not warnings.

E81007: EMPTY TEST

A @Test program must validate something. If it has no assert statements, no assertThrows, and no expected_output.txt companion file, the compiler rejects it:

  @Test
  EmptyTest()
    result <- calculate(5)
    stdout <- Stdout()
    stdout.println($result)   // prints but verifies nothing

This fails with E81007. Fix by adding assert result == 25 or providing expected_output.txt.

E81011: ORPHAN ASSERTION

Assertions must be reachable from at least one @Test program through the call graph:

  helperFunction()
    assert someCondition()    // orphan — no @Test calls this

If no @Test program calls helperFunction() directly or indirectly, the assert is unreachable and the compiler reports E81011. This catches forgotten test wiring.

E81012: PRODUCTION ASSERTION

Assert and assertThrows are only valid in @Test programs or functions called from @Test programs. Using them in production code is a compiler error.

QUALITY METRICS APPLY TO TESTS

Test code is held to the same quality standards as production code:
- Complexity limits (cyclomatic, cognitive, nesting)
- Cohesion and coupling checks
- Variable naming rules (no temp, flag, data, value)
- Reference ordering (alphabetical)
- Unused parameter detection

WHY THIS MATTERS

In Java/Python, a test that calls code but asserts nothing passes silently — false coverage that hides bugs. EK9 makes this a compile error. You cannot have a test that does not test.

See Q804 for why built-in testing. See Q155 for writing tests. See Q310 for code quality metrics.

Example

defines module qa.testdeep.quality.enforcement

  defines function

    compute() as pure
      -> n as Integer
      <- rtn as Integer: n * n

  defines program

    // === VALID TESTS: ASSERT SOMETHING ===

    @Test
    ComputeSquareTest()
      result <- compute(7)
      assert result == 49

    @Test
    ComputeZeroTest()
      result <- compute(0)
      assert result == 0

    TestQualityDemo()
      stdout <- Stdout()
      stdout.println("E81007: empty test (no assertions)")
      stdout.println("E81011: orphan assertion (unreachable)")
      stdout.println("E81012: assert in production code")
      stdout.println("All quality metrics apply to test code")

Common mistakes

E81007 — A @Test program with no assert, no assertThrows, and no expected_output.txt is an empty test — it executes code but validates nothing. Add assertions or provide an expected output file. See ek9 -h E81007 for details.

Incorrect:

@Test
    NoVerification()
      result <- compute(10)
      stdout <- Stdout()
      stdout.println($result)

Correct:

    @Test
    ComputeSquareTest()
      result <- compute(7)
      assert result == 49

E81011 — An assert statement must be reachable from at least one @Test program through the call graph. An unreachable assertion is dead test code. See ek9 -h E81011 for details.

Incorrect:

verifyResult()
      -> value as Integer
      assert value > 0
    // No @Test program calls verifyResult

Correct:

    @Test
    ComputeSquareTest()
      result <- compute(7)
      assert result == 49

    @Test
    ComputeZeroTest()
Other ways to ask this
  • What is an empty test error in EK9?
  • What is an orphan assertion in EK9?
  • How does EK9 prevent meaningless tests?

Coming from another language?

Java: JUnit has no compile-time quality checks — empty tests pass silently. SonarQube can detect some patterns but is optional. Python: pytest allows empty tests, flake8 cannot detect missing assertions. Rust: empty #[test] functions compile and pass. Go: empty Test functions compile and pass. EK9: compile-time rejection of empty tests (E81007), orphan assertions (E81011), and production assertions (E81012).

Keywords: empty, assertion, enforce, E81007, quality, compile, validate, orphan, E81012, E81011