<!-- Source: https://docs.biosimulant.com/how-to/library/test-biomodule -->

# 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

```python

from src.my_module import PopulationCounter

def test_ports_are_declared():
    mod = PopulationCounter(initial_count=100)
    assert "deaths" in mod.inputs()
    assert "population_state" in mod.outputs()

def test_advance_window_updates_state():
    mod = PopulationCounter(initial_count=100, growth_rate=0.1)
    mod.advance_window(0.0, 1.0)
    snap = mod.snapshot()
    assert snap["count"] == 110

def test_set_inputs_accepts_typed_signal():
    mod = PopulationCounter(initial_count=100, growth_rate=0.0)
    mod.set_inputs(
        {
            "deaths": biosim.ScalarSignal(
                source="stim",
                name="deaths",
                value=5,
                emitted_at=0.0,
                spec=biosim.SignalSpec.scalar(dtype="int64"),
            )
        }
    )
    mod.advance_window(0.0, 1.0)
    assert mod.snapshot()["count"] == 95

def test_snapshot_round_trip():
    mod = PopulationCounter(initial_count=50, growth_rate=0.1)
    mod.advance_window(0.0, 1.0)
    snap = mod.snapshot()

    restored = PopulationCounter(initial_count=0, growth_rate=0.0)
    restored.restore(snap)
    assert restored.snapshot() == snap
```

## Integration test with BioWorld

```python

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 outputs
```

## What to verify

- declared ports match the manifest `io` block
- emitted signals use the correct typed signal class
- `snapshot()` / `restore()` round-trip state correctly
- `visualize()` 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.

```bash
python biosim/scripts/snapshot_biomodule_outputs.py \
  path/to/model-or-lab \
  --duration 1.0 \
  --output snapshots/baseline.json
```

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.

**Info:**

  Prefer testing snapshot/restore over relying on `reset()`. The world does not provide a kernel-level `reset()` API.

## Next steps

- [Create a BioModule](/how-to/library/create-biomodule)
- [Use a BioWorld](/how-to/library/use-bioworld)
