How do I generate test cases with -fuzztest in EK9?

← Fuzzing and Mutation Testing · Ref: Q754

The -fuzztest flag analyses your source code and automatically generates edge-case @Test programs.

BASIC USAGE

  ek9 -fuzztest source.ek9 output.ek9

This reads source.ek9, harvests all functions and types, generates candidate test programs, compiles each to verify correctness, and writes the survivors to output.ek9.

SYMBOL HARVESTING

The generator inspects your source to discover:

  Functions: parameter types, return types, and purity.
  Classes: constructors, operators, and public methods.
  Records: constructors and operators.
  Enumerations: values and constrained ranges.

EDGE-CASE VALUES

For each parameter type, the generator selects meaningful edge-case values:

  Integer: 0, 1, -1, MAX, MIN, boundary values.
  Float: 0.0, -0.0, very small, very large, boundary values.
  String: empty, single char, very long, special characters.
  Boolean: true, false.
  Collections: empty, single item, many items.

COMPILE-CHECK-DISCARD

Each generated test candidate is compiled through PRE_IR_CHECKS. If it fails to compile (type error, missing operator, invalid combination), it is silently discarded. Only compilable, type-correct tests survive into the output file.

OPTIONS

  -n 200          Generate at most 200 candidates (default 200).
  -seed 42        Reproducible test generation.
  -overwrite      Replace existing output file.

OUTPUT FORMAT

The output file is a compilable EK9 module containing @Test programs. Each test calls one function or method with edge-case arguments and prints the result for manual review.

See Q749 for fuzzing overview. See Q753 for mutation testing. See Q755 for compile-check-discard philosophy. See Q155 for writing tests. See Q157 for running tests.

Example

defines module qa.fuzzingandmutation.generatetests

  <?-
    Source code that would be analysed by -fuzztest.
    The generator would harvest these functions and create
    @Test programs exercising edge-case inputs.
  -?>

  defines function

    <?-
      Test generator would try: 0, 1, -1, MAX, MIN.
      Edge case: negative numbers should return false.
    -?>
    isPrime()
      -> candidate as Integer
      <- prime as Boolean: false

      two <- 2
      if candidate >= two
        divisor <- two
        foundDivisor <- false
        while divisor * divisor <= candidate and not foundDivisor
          zero <- 0
          if candidate mod divisor == zero
            foundDivisor: true
          divisor: divisor + 1
        prime: not foundDivisor

    <?-
      Test generator would try: empty string, single char,
      already uppercase, mixed case.
    -?>
    isAllUpperCase()
      -> text as String
      <- allUpper as Boolean: false

      if text?
        upper <- text.upperCase()
        allUpper: text == upper

  defines program

    GenerateTestsDemo()
      stdout <- Stdout()

      for candidate in [1, 2, 3, 4, 5, 17, 20, 97]
        stdout.println(`${candidate} prime: ${isPrime(candidate)}`)

      for word in ["HELLO", "Hello", "world", "EK9"]
        stdout.println(`${word} all upper: ${isAllUpperCase(word)}`)
Other ways to ask this
  • What is the ek9 -fuzztest flag for?
  • How does EK9 automatically generate unit tests?
  • How do I use EK9 test generation for edge cases?

Coming from another language?

Java: no built-in test generation, use EvoSuite or Randoop (external, bytecode-level). Python: Hypothesis generates property-based tests (requires writing strategies). Rust: proptest for property-based testing (requires writing arbitraries). Go: go test -fuzz generates inputs but not full test functions. EK9: ek9 -fuzztest generates complete @Test programs from source analysis, compile-checked for correctness.

Keywords: check, candidate, case, test, harvest, edge, boundary, generate, symbol, fuzztest, discard, compile, generation