Skip to content

Testing

The COOM DSL has support for regression tests that simulate configuration sessions. At runtime, each test is executed by the reasoning engine.

A test case is a COOM block, similar to structure or behavior, with one key difference: statements in a test are evaluated strictly in sequence.

  • Define a test with a test { ... } block.
    • To define a test for a specific structure, provide its name like test Wheel { ... }.
    • Without a name, the test is defined at the root level.
  • The test body contains a sequence of statements (order matters, unlike in behavior).
  • Execution starts from an empty configuration:
    • Instances required by the minimum cardinality of features are created automatically.
    • All other instances must be created explicitly.

Minimal example

// test defined at root level
test {
    // set feature "wheelSupport" to option "Yes"
    set wheelSupport = Yes
    // assert that option "W14" remains selectable for feature "wheels"
    isAvailable wheels = W14
}

Test statements

The following statements are available inside a test block.

1. define <name> = <expression>

Creates a local alias <name> for a path or value, usable within the same test { ... } block only.

test {
    define rearSize = root.wheels.rearWheel.size
    // "rearSize" can now be used directly
}

2. load <name>

Loads an existing configuration into the test environment and verifies that it is satisfiable. In KnowWE, configurations can be loaded from stored attachments; outside KnowWE, for example from files.

test {
    load "kids-bike-default"
}

3. set <path> and set <path> = <value>

Set statements have three functions:

  • Creates instances if needed.
  • Assigns feature values.
  • Verifies that the resulting configuration is satisfiable.

Instances are created automatically when:

  • Setting a value on a not-yet-existing instance: set bags[1].size = small
  • Setting a subrange where instances do not yet exist: set bags[2..3].size = small
  • Explicitly setting a structural feature: set bags (creates all required bags) or set bags[3..4]

Note: set bags.size = small updates only existing bags instances.

test {
    // assign concrete values
    set wheelSupport = Yes
    set wheels = W14

    // ensure that 6 bags exist (indices 0..5)
    set bags[0..5]

    // set the size of those 6 existing bags to "small"
    set bags.size = small

    // create instances 7 and 8 and set their size to "big"
    set bags[6..7].size = big
}

4. remove <path>

Removes one or more feature values at <path>. Removal is assumed to be always valid; no satisfiability check is performed.

test {
    remove wheels
    remove bags[0..3]
}

5. reset <path>

Clears all values at <path>. If <path> points to an instance, all of its descendant values are cleared recursively. Instances are not removed. Reset is assumed to be always valid; no satisfiability check is performed.

test {
    reset bike.frontWheel
    reset root // clears the entire configuration
}

6. isAvailable <path> = <value>

For single-valued enumeration features only. Checks the set of available options at <path> and asserts that <value> is still selectable.

test {
    isAvailable wheels = W14
}

7. isBlocked <path> = <value>

For single-valued enumeration features only. The negation of isAvailable: asserts that <value> is not selectable at <path>.

test {
    isBlocked wheels = W18
}

8. isFixed <path> and isFixed <path> = <value>

Solves the configuration and asserts that each feature at <path> has exactly one remaining value in the solution space. Without = <value>, it only checks uniqueness; with = <value>, it also checks equality.

test {
    isFixed bike.size
    isFixed wheels = W14
}

9. isShown <path> and isShown <path> = <value>

Solves the configuration and asserts that:

  • the feature at <path> is visible (not hidden), and
  • its value is at least a default (i.e., not solely a random choice by the engine),
  • and, if = <value> is provided, that the value matches.
test {
    isShown color
    isShown color = Yellow
}

10. isEmpty <path>

Solves the configuration and asserts that the feature at <path> either has no value or only a random choice (implying multiple values remain possible).

test {
    isEmpty accessories
}

Annotations

Test cases have to well known annotations:

  • @label on a test block to provide a human-readable name.
  • @explanation on individual statements to document intent.

Example:

@label = "Color Test 1"
test {
    @explanation = "At the start, yellow must always be available"
    isAvailable color = Yellow
}