How to Test a BioModule
Current-kernel modules are plain Python objects. Test them directly with pytest, then add a small integration test with a real BioWorld.
Unit tests
import biosimulant as biosim
from src.my_module import PopulationCounter
def window_context():
return biosim.ExecutionContext(
policy=biosim.ExecutionPolicy.EACH_WINDOW,
run_start=0.0,
run_end=1.0,
window_start=0.0,
window_end=1.0,
)
def test_ports_are_declared():
mod = PopulationCounter(initial_count=100)
assert "deaths" in mod.inputs()
assert "population_state" in mod.outputs()
def test_execute_updates_state():
mod = PopulationCounter(initial_count=100, growth_rate=0.1)
mod.execute({}, context=window_context())
snap = mod.snapshot()
assert snap["count"] == 110
def test_execute_accepts_typed_signal():
mod = PopulationCounter(initial_count=100, growth_rate=0.0)
inputs = {
"deaths": biosim.ScalarSignal(
source="stim",
name="deaths",
value=5,
emitted_at=0.0,
spec=biosim.SignalSpec.scalar(dtype="int64"),
)
}
mod.execute(inputs, context=window_context())
assert mod.snapshot()["count"] == 95
def test_snapshot_round_trip():
mod = PopulationCounter(initial_count=50, growth_rate=0.1)
mod.execute({}, context=window_context())
snap = mod.snapshot()
restored = PopulationCounter(initial_count=0, growth_rate=0.0)
restored.restore(snap)
assert restored.snapshot() == snapIntegration test with BioWorld
import biosimulant as biosim
from src.my_module import PopulationCounter
def test_world_run_collects_outputs():
world = biosim.BioWorld(communication_step=1.0)
builder = biosim.WiringBuilder(world)
builder.add("population", PopulationCounter(initial_count=50, growth_rate=0.05))
builder.apply()
world.run(duration=5.0)
outputs = world.get_outputs("population")
assert "population_state" in outputsFor canonical modules, test policy and invocation count through BioWorld:
class CountingPredictor(biosim.BioModule):
execution_policy = biosim.ExecutionPolicy.ONCE_BEFORE_RUN
def __init__(self):
self.calls = 0
def outputs(self):
return {"score": biosim.SignalSpec.scalar(dtype="float64")}
def execute(self, inputs, *, context):
self.calls += 1
return {"score": 0.5}
def test_predictor_runs_once_per_run():
predictor = CountingPredictor()
world = biosim.BioWorld(communication_step=0.1)
world.add_biomodule("predictor", predictor)
world.run(duration=1.0)
assert predictor.calls == 1
assert world.get_outputs("predictor")["score"].emitted_at == 0.0What to verify
- declared ports match the manifest
ioblock - emitted signals use the correct typed signal class
- canonical policy, dependency readiness, invocation count, and boundary timestamp are correct
snapshot()/restore()round-trip state correctlyvisualize()returns transport-safe JSON data when present
Snapshot regression checks
For refactors that should preserve behavior, capture a normalized output
snapshot before and after the change. The script lives in the biosim source
repository. pip install biosimulant does not include it, so run it from a
checkout:
git clone https://github.com/Biosimulant/biosim.git
cd biosim
python scripts/snapshot_biomodule_outputs.py \
path/to/model-or-lab \
--duration 1.0 \
--output snapshots/baseline.jsonAfter the change, run it again with --compare snapshots/baseline.json. The
script fails if the new snapshot differs.
The snapshot includes declared input/output specs, emitted signals, module or
world state, and visual JSON. Dependency installation is opt-in with
--install-deps, which keeps heavyweight simulator and ML stacks explicit.
Prefer testing snapshot/restore over relying on reset(). The world does not provide a kernel-level reset() API.