# cargo-test-filter
A cargo subcommand for intelligent test filtering. Run only the tests you need—by tag, type, or pattern.
## Problem
Cargo's built-in test filtering has limitations:
- **No way to isolate test types**: `cargo test` runs both unit and integration tests together
- **String prefix matching only**: No semantic filtering by tags or attributes
- **No function-level tag filtering**: You can't tag individual tests and run only tagged ones
GitHub issues [#8396](https://github.com/rust-lang/cargo/issues/8396) and [#8282](https://github.com/rust-lang/cargo/issues/8282) document these pain points.
## Solution
`cargo-test-filter` provides **function-level test filtering** with:
- **Type isolation**: Run only integration tests or only unit tests
- **Tag-based filtering**: Mark tests with tags and run only what you need
- **Pattern matching**: Filter by test name or path patterns
- **Test discovery**: List all tests with their tags before running
## Installation
```bash
cargo install cargo-test-filter
```
Or build from source:
```bash
git clone https://github.com/johnproblems/cargo-test-filter
cd cargo-test-filter
cargo install --path .
```
## Quick Start
### Tag Your Tests
Use comment-based tags (no proc macros required):
```rust
// @tag: fast
// @tag: api
#[test]
fn test_api_endpoint() {
// ...
}
// @tag: slow
// @tag: database
#[test]
fn test_database_migration() {
// ...
}
```
Or use attribute syntax:
```rust
#[test_tag("fast")]
#[test]
fn test_quick_calculation() {
// ...
}
```
### Run Filtered Tests
```bash
# Run only tests tagged "fast"
cargo test-filter --tag fast
# Run only integration tests
cargo test-filter --integration
# Run unit tests excluding slow ones
cargo test-filter --unit --exclude-tag slow
# List all tests with their tags
cargo test-filter --list
# Filter by test name pattern
cargo test-filter --name api
# Combine filters
cargo test-filter --integration --tag database
```
## Features
### Implemented
- **`--integration`**: Run only integration tests (tests in `tests/` directory)
- **`--unit`**: Run only unit tests (tests in `src/` files)
- **`--tag <TAG>`**: Filter by tag (comma-separated for multiple: `--tag fast,api`)
- **`--exclude-tag <TAG>`**: Exclude tests with these tags
- **`--name <PATTERN>`**: Filter tests by name pattern
- **`--path <PATTERN>`**: Filter tests by file path pattern
- **`--list`**: List matching tests without running them
- **`-v, --verbose`**: Show detailed output including discovered tests and timing
- **Function-level filtering**: Tags are associated with individual test functions, not files
### Tag Syntax
Two formats are supported:
```rust
// Comment-based (recommended - no dependencies needed)
// @tag: fast
#[test]
fn my_test() {}
// Attribute-based
#[test_tag("fast")]
#[test]
fn my_test() {}
```
Tags must appear immediately before the `#[test]` attribute.
## Usage Examples
### CI Pipeline
```yaml
# GitHub Actions example
jobs:
fast-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run fast tests
run: cargo test-filter --tag fast
integration-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run integration tests
run: cargo test-filter --integration
slow-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run slow tests
run: cargo test-filter --tag slow
```
### Development Workflow
```bash
# Quick iteration - run only fast tests
cargo test-filter --tag fast
# Before commit - run everything except slow tests
cargo test-filter --exclude-tag slow
# Debug a specific area
cargo test-filter --name auth --verbose
# See what tests exist
cargo test-filter --list
cargo test-filter --tag database --list
```
### Verbose Output
```bash
$ cargo test-filter --tag fast -v
cargo-test-filter v0.1.0
Filters: tags: fast
Project root: /home/user/my-project
Discovered 25 test function(s) in 45.23ms
- api_test::test_fast_endpoint (tags: ["fast", "api"])
- db_test::test_quick_query (tags: ["fast", "database"])
- lib::test_calculation (tags: ["fast", "unit"])
...
Filtered to 3 test function(s)
Running 3 test function(s)...
```
## How It Works
1. **Discovery**: Scans `tests/` and `src/` directories for test files
2. **Parsing**: Extracts individual test functions and their associated tags
3. **Filtering**: Applies your filter criteria at the function level
4. **Execution**: Runs only matching tests using `cargo test --exact`
Unlike file-level filtering, this tool identifies which specific test *functions* match your criteria, so if you have 10 tests in a file and only 2 are tagged "fast", only those 2 will run.
## Comparison with cargo test
| Filter by test type | Limited (`--lib`, `--test`) | Yes (`--integration`, `--unit`) |
| Tag-based filtering | No | Yes |
| Function-level tags | No | Yes |
| Exclude by tag | No | Yes (`--exclude-tag`) |
| List tests with tags | No | Yes (`--list`) |
| Pass-through args | Yes | Yes |
## Limitations
- **Compile time**: Tests in matching files are still compiled (Rust compiles at the file level). The tool optimizes *which tests run*, not compilation.
- **Doc tests**: Not yet supported
- **Workspaces**: Currently works in single-crate projects
- **Async test frameworks**: Supports `#[tokio::test]` and `#[async_std::test]` detection
## CLI Reference
```
cargo test-filter [OPTIONS]
Options:
--integration Run only integration tests
--unit Run only unit tests
--tag <TAG> Filter by tag (comma-separated)
--exclude-tag <TAG> Exclude tests with these tags
--name <PATTERN> Filter by test name pattern
--path <PATTERN> Filter by file path pattern
--list List matching tests without running
--timeout <SECS> Test timeout in seconds (planned)
-v, --verbose Show verbose output
-h, --help Print help
-V, --version Print version
Additional arguments after -- are passed to cargo test.
```
## Contributing
Contributions welcome! Areas for improvement:
- [ ] Workspace support
- [ ] Doc test filtering
- [ ] JSON output for CI integration
- [ ] Per-test timeout enforcement
- [ ] IDE integration (rust-analyzer hints)
## License
MIT OR Apache-2.0