Testing guide
Cerebro uses a multi-layer testing strategy across its four crates.
Running tests
cargo test --workspace # All tests
cargo test -p cerebro-core # Core library only
cargo test -p cerebro-mcp # MCP server only
cargo test -p cerebro-tui # TUI only
cargo test -- --nocapture # Show stdout during tests
Test layers
Unit tests
Each module contains #[cfg(test)] blocks testing individual functions, methods,
and state transitions. These are the fastest and most numerous tests.
Examples:
- Collector parsing, including TODO regular expression matching and git commit parsing
- Action enum serialization/deserialization
- Key binding resolution
- Input mode state checks
- Config loading and validation
Integration tests
The TUI crate uses ratatui::backend::TestBackend to render components to an
in-memory buffer and assert on the rendered content:
#![allow(unused)]
fn main() {
let backend = TestBackend::new(80, 24);
let mut terminal = Terminal::new(backend)?;
// Render component, assert buffer string
}
For full app lifecycle tests, construct Home directly with mock dependencies,
call set_cerebro_config() and do_initial_load_sync().await, then render the
terminal and assert against it.
Navigation tests verify home.view_name() changes, not just that text appears
somewhere in the buffer, since sidebar text is always visible.
Behavior-driven development tests
Write user-facing scenarios in Gherkin with step definitions in tests/cucumber.rs. The BDD workflow:
- Write Gherkin scenarios describing user behavior in terms of what the user does and sees
- Write step definitions that assert against real component state, such as
home.view_name() - Run: must go red before implementation changes
- Implement to make it green
- Commit only when the full suite passes
Step definitions must never assert against buffer text that happens to match: that produces false positives. Always check component state directly.
System tests with Ghostty
The TUI has system-level tests using Ghostty devtools for:
- Terminal lifecycle, including startup, shutdown, and panic recovery
- Layout adaptation on resize
- UI responsiveness during long operations
These tests run against the actual binary in a real terminal, not a mock backend.
Test coverage by crate
| Crate | Unit | Integration | BDD | System |
|---|---|---|---|---|
cerebro | Config, cache, generators | — | — | — |
cerebro-core | Collectors, types, queries | — | — | — |
cerebro-mcp | Server setup | — | — | — |
cerebro-tui | Components, actions, keybindings | Full app render | User scenarios | Ghostty lifecycle |
Adding tests
Adding a new component: add at least one snapshot test using assert_buffer_snapshot! to verify rendered output.
Adding a new function or method: add unit tests for happy path and edge cases.
Fixing a bug: add a regression test that would have caught the bug.
Refactoring: ensure existing tests still pass. Add tests if coverage was zero.