Install
$ agentstack add skill-maxenko-claude-skills-rust-test-separate ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Rust Test Separator
You separate inline #[cfg(test)] mod tests { ... } blocks from Rust implementation files into dedicated test files, following the conventions used by tokio, bevy, and axum.
Critical Principles
1. Preserve the module hierarchy. The extracted test module must remain a child of the implementation module so use super::* continues to work and private function access is retained. This means using the foo.rs + foo/tests.rs pattern (or #[cfg(test)] mod tests; declaration), NOT moving tests to tests/ at the top level.
2. Never move unit tests to tests/ (integration test directory). The tests/ directory creates separate crates that cannot access private or pub(crate) items. Only integration tests belong there. This skill handles unit test extraction only.
3. Always keep #[cfg(test)] on the module declaration. After extraction, the implementation file must have #[cfg(test)] mod tests; — without #[cfg(test)], the test file compiles into release builds.
4. Don't separate small test modules. If the #[cfg(test)] mod tests block is under ~150 lines, leave it inline. Extraction adds indirection without meaningful benefit. The user can override this with explicit instructions.
Process
Phase 1: Scan, Plan & Confirm
Determine the target scope from $ARGUMENTS:
- Single file: If
$ARGUMENTSis a.rsfile path, read that file directly. Skip glob/grep. - Directory or omitted: Glob
src/**/*.rs(relative to the argument path or cwd), then grep for#[cfg(test)]as a coarse filter.
Filtering candidates. The grep is a pre-filter. When reading each file, skip it if:
- It contains
#[cfg(test)] mod tests;(semicolon, no braces) — already separated. - The
#[cfg(test)]is only on individual functions orusestatements, not amodblock. - The test module has a
#[path = "..."]attribute — warn the user and skip (non-standard layout that extraction could break).
For each valid candidate with an inline #[cfg(test)] mod ... { ... } block, record:
- File path
- Estimated line count of the test module
- Whether the file already uses directory module form (
mod.rspattern orfoo.rs+foo/directory)
Note: files in src/bin/ are valid candidates — the same extraction mechanics apply.
Crate root files (lib.rs, main.rs): Extracting from these creates src/lib/tests.rs or src/main/tests.rs, which is technically valid but unconventional. Flag these to the user with a note that most projects keep crate root tests inline, and only extract if the user explicitly confirms.
Present a table with the planned action:
| File | Test Lines | Case | Action |
|------|-----------|------|--------|
| src/parser.rs | 340 | A | Extract |
| src/lib.rs | 45 | - | Skip (small, crate root) |
| src/utils/mod.rs | 220 | B | Extract |
Case definitions:
- Case A — File needs directory restructuring. The file is a standalone
foo.rswith no existingfoo/directory. Extraction requires creatingfoo/and either convertingfoo.rs→foo/mod.rs(mod.rs convention) or keepingfoo.rsand addingfoo/tests.rsalongside it (Rust 2018+ convention). - Case B — Directory already exists. The file is already
foo/mod.rsor has an existingfoo/directory. Just addtests.rsinside the existing directory.
Action criteria:
- Extract: Test block >= 150 lines (or user explicitly requested this file)
- Skip: Test block &1
If there are errors:
- Read the error output carefully
- Common fixes: adjust `use` paths, add `pub(crate)` to items that tests need across module boundaries, fix `super::` paths
- Apply fixes and re-check
- If a fix requires making a private item `pub(crate)`, flag this to the user — it may indicate the test should actually remain inline
Report the final result: which files were extracted, any visibility changes required, and the `cargo check` outcome. Optionally suggest running `cargo test` to confirm tests still pass at runtime.
## Module Convention Detection
Before any file moves, determine which module convention the project uses:
**`mod.rs` convention (traditional)**:
src/parser/mod.rs <- module root src/parser/lexer.rs <- sub-module
**Non-`mod.rs` convention (Rust 2018+)**:
src/parser.rs <- module root src/parser/lexer.rs <- sub-module
Check existing directory modules in the project. Use whichever convention is already in use. If the project has no directory modules yet, prefer the Rust 2018+ convention (keeping `foo.rs` alongside `foo/` directory) unless the user specifies otherwise.
## Edge Cases
- **Multiple `#[cfg(test)]` blocks in one file**: Merge into a single `tests.rs`, preserving all contents. If merged blocks contain duplicate item names, report the conflict to the user rather than silently breaking compilation.
- **Nested `#[cfg(test)]` modules** (e.g., `mod tests` containing `mod integration`): Preserve the nesting structure in `tests.rs`.
- **Test modules with names other than `tests`**: Preserve the original name. Use `#[cfg(test)] mod original_name;` in the declaration.
- **`#[cfg(test)]` on individual functions** (not in a module): Leave these alone — they're a different pattern.
- **`#[cfg(test)]` on `impl` blocks**: Leave these in the implementation file. These are test helper methods on the struct itself (e.g., builder methods for test fixtures) and should stay near the type definition.
- **Test modules using `use crate::...` instead of `use super::*`**: Fully qualified `use crate::...` paths need no adjustment after extraction. Only `use super::...` paths are affected by the module depth change, and only for imports moved from *outside* the test module (see Step 4).
- **Files that are already `tests.rs`**: Skip. Don't re-extract.
- **Workspace crates**: Process one crate at a time. If `$ARGUMENTS` points to a workspace root, ask which crate(s) to process.
- **`build.rs`**: Excluded — it is a separate build script compilation unit, not a library/binary module.
Consult `references/rust-test-module-reference.md` for visibility rules, empirical project data, and rare edge case patterns.
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [maxenko](https://github.com/maxenko)
- **Source:** [maxenko/claude-skills](https://github.com/maxenko/claude-skills)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.