Lesson 10.2 · Builds, testing, and source studies· 2 min read
Testing inert models and interpreting observations
Test a local behavioral model and distinguish expected outcomes, observed outcomes, and untested assumptions.
- Platform:
- Cross-platform
- Language:
- Python
- Difficulty:
- Intermediate
What you will learn
Test a local behavioral model and distinguish expected outcomes, observed outcomes, and untested assumptions.
Before you begin: State machines, API results, and build provenance.
Make the lesson's claims testable
An educational model should state what it accepts and what result it produces. Tests then check those claims against representative cases. This is especially useful when a malware source study depends on a subtle contract, such as true-on-equality or selection-before-completion.
The example below models dispatch selection only. It returns a label from a local dictionary. It neither invokes handlers nor constructs any system or network operation. Its small scope makes it possible to test exactly what the lesson claims without adding unrelated capabilities.
A bounded test example
handlers = {1: "status demonstration", 2: "version demonstration"}
def select_label(command_id):
if type(command_id) is not int:
return "invalid"
return handlers.get(command_id, "unknown")
assert select_label(1) == "status demonstration"
assert select_label(2) == "version demonstration"
assert select_label(99) == "unknown"
assert select_label("1") == "invalid"
assert select_label(True) == "invalid"
print("five selection checks passed")
Explain the boundaries
The exact type check prevents Python's Boolean values from being accepted as integer identifiers in this model. The absent identifier tests the unknown path, while the string tests a different representation. Those are distinct cases: an unknown value of the right type and a value of the wrong type should not be conflated.
Passing these tests establishes the behavior of this function for these inputs. It does not validate a network parser, a native dispatcher, or every possible implementation. A test result inherits the scope of the model being tested.
Observability is part of the explanation
A log message reports what the code chose to record. To interpret it, find where it is emitted relative to validation, selection, execution, and completion. An early message can remain visible even when a later step fails. A missing message can reflect an unobserved path or missing instrumentation rather than absence of behavior.
When writing a lesson, put the expected result beside the example and explain a failing case. If a fixture is synthetic, say so. A demonstration that resembles a real data structure should not be mislabeled as authentic malware output.
Exercise
Add a test for -1 and predict the result. Then decide whether these tests establish that a selected operation succeeded. What extra information would be needed to test that separate claim?
Check your understanding
The negative identifier returns unknown. No operation is performed in this model, so the tests establish selection behavior only. To discuss execution success, first define that operation's contract and its observable result instead of reusing the selection result as proof.