[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M73FJECG8QXW7RXT606GYMES":3,"skill-same:01M73FJECG8QXW7RXT606GYMES":49},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":25,"commitSha":26,"skillDirectory":27,"forksCount":28,"repositoryHtmlUrl":29,"repositoryHomepageUrl":30,"ownerHtmlUrl":31,"ownerBlogUrl":32,"ownerDescription":33,"updatedAt":34,"install":35,"resources":48},"01M73FJECG8QXW7RXT606GYMES","rust-testing",null,"Rust testing patterns including unit tests, integration tests, async testing, property-based testing, mocking, and coverage. Follows TDD methodology.","Horonomos-laps\u002FYana-AI","Horonomos-laps","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F355299122?v=4","01M76B3QPXE88ET2SQPDPVATZT"," Horonomos-laps","01M72ZQRJPCYPSSWT4D00VJR2A",13,"Apache-2.0","https:\u002F\u002Fgithub.com\u002FHoronomos-laps\u002FYana-AI\u002Fblob\u002Fmain\u002Fcore\u002Fskills\u002Frust-testing\u002FSKILL.md",[],[],"2026-11-11 15:11:14",false,"---\nname: rust-testing\ndescription: Rust testing patterns including unit tests, integration tests, async testing, property-based testing, mocking, and coverage. Follows TDD methodology.\norigin: ECC\n---\n\n# Rust Testing Patterns\n\nComprehensive Rust testing patterns for writing reliable, maintainable tests following TDD methodology.\n\n## When to Use\n\n- Writing new Rust functions, methods, or traits\n- Adding test coverage to existing code\n- Creating benchmarks for performance-critical code\n- Implementing property-based tests for input validation\n- Following TDD workflow in Rust projects\n\n## How It Works\n\n1. **Identify target code** — Find the function, trait, or module to test\n2. **Write a test** — Use `#[test]` in a `#[cfg(test)]` module, rstest for parameterized tests, or proptest for property-based tests\n3. **Mock dependencies** — Use mockall to isolate the unit under test\n4. **Run tests (RED)** — Verify the test fails with the expected error\n5. **Implement (GREEN)** — Write minimal code to pass\n6. **Refactor** — Improve while keeping tests green\n7. **Check coverage** — Use cargo-llvm-cov, target 80%+\n\n## TDD Workflow for Rust\n\n### The RED-GREEN-REFACTOR Cycle\n\n```\nRED     → Write a failing test first\nGREEN   → Write minimal code to pass the test\nREFACTOR → Improve code while keeping tests green\nREPEAT  → Continue with next requirement\n```\n\n### Step-by-Step TDD in Rust\n\n```rust\n\u002F\u002F RED: Write test first, use todo!() as placeholder\npub fn add(a: i32, b: i32) -> i32 { todo!() }\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn test_add() { assert_eq!(add(2, 3), 5); }\n}\n\u002F\u002F cargo test → panics at 'not yet implemented'\n```\n\n```rust\n\u002F\u002F GREEN: Replace todo!() with minimal implementation\npub fn add(a: i32, b: i32) -> i32 { a + b }\n\u002F\u002F cargo test → PASS, then REFACTOR while keeping tests green\n```\n\n## Unit Tests\n\n### Module-Level Test Organization\n\n```rust\n\u002F\u002F src\u002Fuser.rs\npub struct User {\n    pub name: String,\n    pub email: String,\n}\n\nimpl User {\n    pub fn new(name: impl Into\u003CString>, email: impl Into\u003CString>) -> Result\u003CSelf, String> {\n        let email = email.into();\n        if !email.contains('@') {\n            return Err(format!(\"invalid email: {email}\"));\n        }\n        Ok(Self { name: name.into(), email })\n    }\n\n    pub fn display_name(&self) -> &str {\n        &self.name\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn creates_user_with_valid_email() {\n        let user = User::new(\"Alice\", \"alice@example.com\").unwrap();\n        assert_eq!(user.display_name(), \"Alice\");\n        assert_eq!(user.email, \"alice@example.com\");\n    }\n\n    #[test]\n    fn rejects_invalid_email() {\n        let result = User::new(\"Bob\", \"not-an-email\");\n        assert!(result.is_err());\n        assert!(result.unwrap_err().contains(\"invalid email\"));\n    }\n}\n```\n\n### Assertion Macros\n\n```rust\nassert_eq!(2 + 2, 4);                                    \u002F\u002F Equality\nassert_ne!(2 + 2, 5);                                    \u002F\u002F Inequality\nassert!(vec![1, 2, 3].contains(&2));                     \u002F\u002F Boolean\nassert_eq!(value, 42, \"expected 42 but got {value}\");    \u002F\u002F Custom message\nassert!((0.1_f64 + 0.2 - 0.3).abs() \u003C f64::EPSILON);   \u002F\u002F Float comparison\n```\n\n## Error and Panic Testing\n\n### Testing `Result` Returns\n\n```rust\n#[test]\nfn parse_returns_error_for_invalid_input() {\n    let result = parse_config(\"}{invalid\");\n    assert!(result.is_err());\n\n    \u002F\u002F Assert specific error variant\n    let err = result.unwrap_err();\n    assert!(matches!(err, ConfigError::ParseError(_)));\n}\n\n#[test]\nfn parse_succeeds_for_valid_input() -> Result\u003C(), Box\u003Cdyn std::error::Error>> {\n    let config = parse_config(r#\"{\"port\": 8080}\"#)?;\n    assert_eq!(config.port, 8080);\n    Ok(()) \u002F\u002F Test fails if any ? returns Err\n}\n```\n\n### Testing Panics\n\n```rust\n#[test]\n#[should_panic]\nfn panics_on_empty_input() {\n    process(&[]);\n}\n\n#[test]\n#[should_panic(expected = \"index out of bounds\")]\nfn panics_with_specific_message() {\n    let v: Vec\u003Ci32> = vec![];\n    let _ = v[0];\n}\n```\n\n## Integration Tests\n\n### File Structure\n\n```text\nmy_crate\u002F\n├── src\u002F\n│   └── lib.rs\n├── tests\u002F              # Integration tests\n│   ├── api_test.rs     # Each file is a separate test binary\n│   ├── db_test.rs\n│   └── common\u002F         # Shared test utilities\n│       └── mod.rs\n```\n\n### Writing Integration Tests\n\n```rust\n\u002F\u002F tests\u002Fapi_test.rs\nuse my_crate::{App, Config};\n\n#[test]\nfn full_request_lifecycle() {\n    let config = Config::test_default();\n    let app = App::new(config);\n\n    let response = app.handle_request(\"\u002Fhealth\");\n    assert_eq!(response.status, 200);\n    assert_eq!(response.body, \"OK\");\n}\n```\n\n## Async Tests\n\n### With Tokio\n\n```rust\n#[tokio::test]\nasync fn fetches_data_successfully() {\n    let client = TestClient::new().await;\n    let result = client.get(\"\u002Fdata\").await;\n    assert!(result.is_ok());\n    assert_eq!(result.unwrap().items.len(), 3);\n}\n\n#[tokio::test]\nasync fn handles_timeout() {\n    use std::time::Duration;\n    let result = tokio::time::timeout(\n        Duration::from_millis(100),\n        slow_operation(),\n    ).await;\n\n    assert!(result.is_err(), \"should have timed out\");\n}\n```\n\n## Test Organization Patterns\n\n### Parameterized Tests with `rstest`\n\n```rust\nuse rstest::{rstest, fixture};\n\n#[rstest]\n#[case(\"hello\", 5)]\n#[case(\"\", 0)]\n#[case(\"rust\", 4)]\nfn test_string_length(#[case] input: &str, #[case] expected: usize) {\n    assert_eq!(input.len(), expected);\n}\n\n\u002F\u002F Fixtures\n#[fixture]\nfn test_db() -> TestDb {\n    TestDb::new_in_memory()\n}\n\n#[rstest]\nfn test_insert(test_db: TestDb) {\n    test_db.insert(\"key\", \"value\");\n    assert_eq!(test_db.get(\"key\"), Some(\"value\".into()));\n}\n```\n\n### Test Helpers\n\n```rust\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    \u002F\u002F\u002F Creates a test user with sensible defaults.\n    fn make_user(name: &str) -> User {\n        User::new(name, &format!(\"{name}@test.com\")).unwrap()\n    }\n\n    #[test]\n    fn user_display() {\n        let user = make_user(\"alice\");\n        assert_eq!(user.display_name(), \"alice\");\n    }\n}\n```\n\n## Property-Based Testing with `proptest`\n\n### Basic Property Tests\n\n```rust\nuse proptest::prelude::*;\n\nproptest! {\n    #[test]\n    fn encode_decode_roundtrip(input in \".*\") {\n        let encoded = encode(&input);\n        let decoded = decode(&encoded).unwrap();\n        assert_eq!(input, decoded);\n    }\n\n    #[test]\n    fn sort_preserves_length(mut vec in prop::collection::vec(any::\u003Ci32>(), 0..100)) {\n        let original_len = vec.len();\n        vec.sort();\n        assert_eq!(vec.len(), original_len);\n    }\n\n    #[test]\n    fn sort_produces_ordered_output(mut vec in prop::collection::vec(any::\u003Ci32>(), 0..100)) {\n        vec.sort();\n        for window in vec.windows(2) {\n            assert!(window[0] \u003C= window[1]);\n        }\n    }\n}\n```\n\n### Custom Strategies\n\n```rust\nuse proptest::prelude::*;\n\nfn valid_email() -> impl Strategy\u003CValue = String> {\n    (\"[a-z]{1,10}\", \"[a-z]{1,5}\")\n        .prop_map(|(user, domain)| format!(\"{user}@{domain}.com\"))\n}\n\nproptest! {\n    #[test]\n    fn accepts_valid_emails(email in valid_email()) {\n        assert!(User::new(\"Test\", &email).is_ok());\n    }\n}\n```\n\n## Mocking with `mockall`\n\n### Trait-Based Mocking\n\n```rust\nuse mockall::{automock, predicate::eq};\n\n#[automock]\ntrait UserRepository {\n    fn find_by_id(&self, id: u64) -> Option\u003CUser>;\n    fn save(&self, user: &User) -> Result\u003C(), StorageError>;\n}\n\n#[test]\nfn service_returns_user_when_found() {\n    let mut mock = MockUserRepository::new();\n    mock.expect_find_by_id()\n        .with(eq(42))\n        .times(1)\n        .returning(|_| Some(User { id: 42, name: \"Alice\".into() }));\n\n    let service = UserService::new(Box::new(mock));\n    let user = service.get_user(42).unwrap();\n    assert_eq!(user.name, \"Alice\");\n}\n\n#[test]\nfn service_returns_none_when_not_found() {\n    let mut mock = MockUserRepository::new();\n    mock.expect_find_by_id()\n        .returning(|_| None);\n\n    let service = UserService::new(Box::new(mock));\n    assert!(service.get_user(99).is_none());\n}\n```\n\n## Doc Tests\n\n### Executable Documentation\n\n```rust\n\u002F\u002F\u002F Adds two numbers together.\n\u002F\u002F\u002F\n\u002F\u002F\u002F # Examples\n\u002F\u002F\u002F\n\u002F\u002F\u002F ```\n\u002F\u002F\u002F use my_crate::add;\n\u002F\u002F\u002F\n\u002F\u002F\u002F assert_eq!(add(2, 3), 5);\n\u002F\u002F\u002F assert_eq!(add(-1, 1), 0);\n\u002F\u002F\u002F ```\npub fn add(a: i32, b: i32) -> i32 {\n    a + b\n}\n\n\u002F\u002F\u002F Parses a config string.\n\u002F\u002F\u002F\n\u002F\u002F\u002F # Errors\n\u002F\u002F\u002F\n\u002F\u002F\u002F Returns `Err` if the input is not valid TOML.\n\u002F\u002F\u002F\n\u002F\u002F\u002F ```no_run\n\u002F\u002F\u002F use my_crate::parse_config;\n\u002F\u002F\u002F\n\u002F\u002F\u002F let config = parse_config(r#\"port = 8080\"#).unwrap();\n\u002F\u002F\u002F assert_eq!(config.port, 8080);\n\u002F\u002F\u002F ```\n\u002F\u002F\u002F\n\u002F\u002F\u002F ```no_run\n\u002F\u002F\u002F use my_crate::parse_config;\n\u002F\u002F\u002F\n\u002F\u002F\u002F assert!(parse_config(\"}{invalid\").is_err());\n\u002F\u002F\u002F ```\npub fn parse_config(input: &str) -> Result\u003CConfig, ParseError> {\n    todo!()\n}\n```\n\n## Benchmarking with Criterion\n\n```toml\n# Cargo.toml\n[dev-dependencies]\ncriterion = { version = \"0.5\", features = [\"html_reports\"] }\n\n[[bench]]\nname = \"benchmark\"\nharness = false\n```\n\n```rust\n\u002F\u002F benches\u002Fbenchmark.rs\nuse criterion::{black_box, criterion_group, criterion_main, Criterion};\n\nfn fibonacci(n: u64) -> u64 {\n    match n {\n        0 | 1 => n,\n        _ => fibonacci(n - 1) + fibonacci(n - 2),\n    }\n}\n\nfn bench_fibonacci(c: &mut Criterion) {\n    c.bench_function(\"fib 20\", |b| b.iter(|| fibonacci(black_box(20))));\n}\n\ncriterion_group!(benches, bench_fibonacci);\ncriterion_main!(benches);\n```\n\n## Test Coverage\n\n### Running Coverage\n\n```bash\n# Install: cargo install cargo-llvm-cov (or use taiki-e\u002Finstall-action in CI)\ncargo llvm-cov                    # Summary\ncargo llvm-cov --html             # HTML report\ncargo llvm-cov --lcov > lcov.info # LCOV format for CI\ncargo llvm-cov --fail-under-lines 80  # Fail if below threshold\n```\n\n### Coverage Targets\n\n| Code Type | Target |\n|-----------|--------|\n| Critical business logic | 100% |\n| Public API | 90%+ |\n| General code | 80%+ |\n| Generated \u002F FFI bindings | Exclude |\n\n## Testing Commands\n\n```bash\ncargo test                        # Run all tests\ncargo test -- --nocapture         # Show println output\ncargo test test_name              # Run tests matching pattern\ncargo test --lib                  # Unit tests only\ncargo test --test api_test        # Integration tests only\ncargo test --doc                  # Doc tests only\ncargo test --no-fail-fast         # Don't stop on first failure\ncargo test -- --ignored           # Run ignored tests\n```\n\n## Best Practices\n\n**DO:**\n- Write tests FIRST (TDD)\n- Use `#[cfg(test)]` modules for unit tests\n- Test behavior, not implementation\n- Use descriptive test names that explain the scenario\n- Prefer `assert_eq!` over `assert!` for better error messages\n- Use `?` in tests that return `Result` for cleaner error output\n- Keep tests independent — no shared mutable state\n\n**DON'T:**\n- Use `#[should_panic]` when you can test `Result::is_err()` instead\n- Mock everything — prefer integration tests when feasible\n- Ignore flaky tests — fix or quarantine them\n- Use `sleep()` in tests — use channels, barriers, or `tokio::time::pause()`\n- Skip error path testing\n\n## CI Integration\n\n```yaml\n# GitHub Actions\ntest:\n  runs-on: ubuntu-latest\n  steps:\n    - uses: actions\u002Fcheckout@v4\n    - uses: dtolnay\u002Frust-toolchain@stable\n      with:\n        components: clippy, rustfmt\n\n    - name: Check formatting\n      run: cargo fmt --check\n\n    - name: Clippy\n      run: cargo clippy -- -D warnings\n\n    - name: Run tests\n      run: cargo test\n\n    - uses: taiki-e\u002Finstall-action@cargo-llvm-cov\n\n    - name: Coverage\n      run: cargo llvm-cov --fail-under-lines 80\n```\n\n**Remember**: Tests are documentation. They show how your code is meant to be used. Write them clearly and keep them up to date.\n","# Rust Testing Patterns\n\nComprehensive Rust testing patterns for writing reliable, maintainable tests following TDD methodology.\n\n## When to Use\n\n- Writing new Rust functions, methods, or traits\n- Adding test coverage to existing code\n- Creating benchmarks for performance-critical code\n- Implementing property-based tests for input validation\n- Following TDD workflow in Rust projects\n\n## How It Works\n\n1. **Identify target code** — Find the function, trait, or module to test\n2. **Write a test** — Use `#[test]` in a `#[cfg(test)]` module, rstest for parameterized tests, or proptest for property-based tests\n3. **Mock dependencies** — Use mockall to isolate the unit under test\n4. **Run tests (RED)** — Verify the test fails with the expected error\n5. **Implement (GREEN)** — Write minimal code to pass\n6. **Refactor** — Improve while keeping tests green\n7. **Check coverage** — Use cargo-llvm-cov, target 80%+\n\n## TDD Workflow for Rust\n\n### The RED-GREEN-REFACTOR Cycle\n\n```\nRED     → Write a failing test first\nGREEN   → Write minimal code to pass the test\nREFACTOR → Improve code while keeping tests green\nREPEAT  → Continue with next requirement\n```\n\n### Step-by-Step TDD in Rust\n\n```rust\n\u002F\u002F RED: Write test first, use todo!() as placeholder\npub fn add(a: i32, b: i32) -> i32 { todo!() }\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn test_add() { assert_eq!(add(2, 3), 5); }\n}\n\u002F\u002F cargo test → panics at 'not yet implemented'\n```\n\n```rust\n\u002F\u002F GREEN: Replace todo!() with minimal implementation\npub fn add(a: i32, b: i32) -> i32 { a + b }\n\u002F\u002F cargo test → PASS, then REFACTOR while keeping tests green\n```\n\n## Unit Tests\n\n### Module-Level Test Organization\n\n```rust\n\u002F\u002F src\u002Fuser.rs\npub struct User {\n    pub name: String,\n    pub email: String,\n}\n\nimpl User {\n    pub fn new(name: impl Into\u003CString>, email: impl Into\u003CString>) -> Result\u003CSelf, String> {\n        let email = email.into();\n        if !email.contains('@') {\n            return Err(format!(\"invalid email: {email}\"));\n        }\n        Ok(Self { name: name.into(), email })\n    }\n\n    pub fn display_name(&self) -> &str {\n        &self.name\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn creates_user_with_valid_email() {\n        let user = User::new(\"Alice\", \"alice@example.com\").unwrap();\n        assert_eq!(user.display_name(), \"Alice\");\n        assert_eq!(user.email, \"alice@example.com\");\n    }\n\n    #[test]\n    fn rejects_invalid_email() {\n        let result = User::new(\"Bob\", \"not-an-email\");\n        assert!(result.is_err());\n        assert!(result.unwrap_err().contains(\"invalid email\"));\n    }\n}\n```\n\n### Assertion Macros\n\n```rust\nassert_eq!(2 + 2, 4);                                    \u002F\u002F Equality\nassert_ne!(2 + 2, 5);                                    \u002F\u002F Inequality\nassert!(vec![1, 2, 3].contains(&2));                     \u002F\u002F Boolean\nassert_eq!(value, 42, \"expected 42 but got {value}\");    \u002F\u002F Custom message\nassert!((0.1_f64 + 0.2 - 0.3).abs() \u003C f64::EPSILON);   \u002F\u002F Float comparison\n```\n\n## Error and Panic Testing\n\n### Testing `Result` Returns\n\n```rust\n#[test]\nfn parse_returns_error_for_invalid_input() {\n    let result = parse_config(\"}{invalid\");\n    assert!(result.is_err());\n\n    \u002F\u002F Assert specific error variant\n    let err = result.unwrap_err();\n    assert!(matches!(err, ConfigError::ParseError(_)));\n}\n\n#[test]\nfn parse_succeeds_for_valid_input() -> Result\u003C(), Box\u003Cdyn std::error::Error>> {\n    let config = parse_config(r#\"{\"port\": 8080}\"#)?;\n    assert_eq!(config.port, 8080);\n    Ok(()) \u002F\u002F Test fails if any ? returns Err\n}\n```\n\n### Testing Panics\n\n```rust\n#[test]\n#[should_panic]\nfn panics_on_empty_input() {\n    process(&[]);\n}\n\n#[test]\n#[should_panic(expected = \"index out of bounds\")]\nfn panics_with_specific_message() {\n    let v: Vec\u003Ci32> = vec![];\n    let _ = v[0];\n}\n```\n\n## Integration Tests\n\n### File Structure\n\n```text\nmy_crate\u002F\n├── src\u002F\n│   └── lib.rs\n├── tests\u002F              # Integration tests\n│   ├── api_test.rs     # Each file is a separate test binary\n│   ├── db_test.rs\n│   └── common\u002F         # Shared test utilities\n│       └── mod.rs\n```\n\n### Writing Integration Tests\n\n```rust\n\u002F\u002F tests\u002Fapi_test.rs\nuse my_crate::{App, Config};\n\n#[test]\nfn full_request_lifecycle() {\n    let config = Config::test_default();\n    let app = App::new(config);\n\n    let response = app.handle_request(\"\u002Fhealth\");\n    assert_eq!(response.status, 200);\n    assert_eq!(response.body, \"OK\");\n}\n```\n\n## Async Tests\n\n### With Tokio\n\n```rust\n#[tokio::test]\nasync fn fetches_data_successfully() {\n    let client = TestClient::new().await;\n    let result = client.get(\"\u002Fdata\").await;\n    assert!(result.is_ok());\n    assert_eq!(result.unwrap().items.len(), 3);\n}\n\n#[tokio::test]\nasync fn handles_timeout() {\n    use std::time::Duration;\n    let result = tokio::time::timeout(\n        Duration::from_millis(100),\n        slow_operation(),\n    ).await;\n\n    assert!(result.is_err(), \"should have timed out\");\n}\n```\n\n## Test Organization Patterns\n\n### Parameterized Tests with `rstest`\n\n```rust\nuse rstest::{rstest, fixture};\n\n#[rstest]\n#[case(\"hello\", 5)]\n#[case(\"\", 0)]\n#[case(\"rust\", 4)]\nfn test_string_length(#[case] input: &str, #[case] expected: usize) {\n    assert_eq!(input.len(), expected);\n}\n\n\u002F\u002F Fixtures\n#[fixture]\nfn test_db() -> TestDb {\n    TestDb::new_in_memory()\n}\n\n#[rstest]\nfn test_insert(test_db: TestDb) {\n    test_db.insert(\"key\", \"value\");\n    assert_eq!(test_db.get(\"key\"), Some(\"value\".into()));\n}\n```\n\n### Test Helpers\n\n```rust\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    \u002F\u002F\u002F Creates a test user with sensible defaults.\n    fn make_user(name: &str) -> User {\n        User::new(name, &format!(\"{name}@test.com\")).unwrap()\n    }\n\n    #[test]\n    fn user_display() {\n        let user = make_user(\"alice\");\n        assert_eq!(user.display_name(), \"alice\");\n    }\n}\n```\n\n## Property-Based Testing with `proptest`\n\n### Basic Property Tests\n\n```rust\nuse proptest::prelude::*;\n\nproptest! {\n    #[test]\n    fn encode_decode_roundtrip(input in \".*\") {\n        let encoded = encode(&input);\n        let decoded = decode(&encoded).unwrap();\n        assert_eq!(input, decoded);\n    }\n\n    #[test]\n    fn sort_preserves_length(mut vec in prop::collection::vec(any::\u003Ci32>(), 0..100)) {\n        let original_len = vec.len();\n        vec.sort();\n        assert_eq!(vec.len(), original_len);\n    }\n\n    #[test]\n    fn sort_produces_ordered_output(mut vec in prop::collection::vec(any::\u003Ci32>(), 0..100)) {\n        vec.sort();\n        for window in vec.windows(2) {\n            assert!(window[0] \u003C= window[1]);\n        }\n    }\n}\n```\n\n### Custom Strategies\n\n```rust\nuse proptest::prelude::*;\n\nfn valid_email() -> impl Strategy\u003CValue = String> {\n    (\"[a-z]{1,10}\", \"[a-z]{1,5}\")\n        .prop_map(|(user, domain)| format!(\"{user}@{domain}.com\"))\n}\n\nproptest! {\n    #[test]\n    fn accepts_valid_emails(email in valid_email()) {\n        assert!(User::new(\"Test\", &email).is_ok());\n    }\n}\n```\n\n## Mocking with `mockall`\n\n### Trait-Based Mocking\n\n```rust\nuse mockall::{automock, predicate::eq};\n\n#[automock]\ntrait UserRepository {\n    fn find_by_id(&self, id: u64) -> Option\u003CUser>;\n    fn save(&self, user: &User) -> Result\u003C(), StorageError>;\n}\n\n#[test]\nfn service_returns_user_when_found() {\n    let mut mock = MockUserRepository::new();\n    mock.expect_find_by_id()\n        .with(eq(42))\n        .times(1)\n        .returning(|_| Some(User { id: 42, name: \"Alice\".into() }));\n\n    let service = UserService::new(Box::new(mock));\n    let user = service.get_user(42).unwrap();\n    assert_eq!(user.name, \"Alice\");\n}\n\n#[test]\nfn service_returns_none_when_not_found() {\n    let mut mock = MockUserRepository::new();\n    mock.expect_find_by_id()\n        .returning(|_| None);\n\n    let service = UserService::new(Box::new(mock));\n    assert!(service.get_user(99).is_none());\n}\n```\n\n## Doc Tests\n\n### Executable Documentation\n\n```rust\n\u002F\u002F\u002F Adds two numbers together.\n\u002F\u002F\u002F\n\u002F\u002F\u002F # Examples\n\u002F\u002F\u002F\n\u002F\u002F\u002F ```\n\u002F\u002F\u002F use my_crate::add;\n\u002F\u002F\u002F\n\u002F\u002F\u002F assert_eq!(add(2, 3), 5);\n\u002F\u002F\u002F assert_eq!(add(-1, 1), 0);\n\u002F\u002F\u002F ```\npub fn add(a: i32, b: i32) -> i32 {\n    a + b\n}\n\n\u002F\u002F\u002F Parses a config string.\n\u002F\u002F\u002F\n\u002F\u002F\u002F # Errors\n\u002F\u002F\u002F\n\u002F\u002F\u002F Returns `Err` if the input is not valid TOML.\n\u002F\u002F\u002F\n\u002F\u002F\u002F ```no_run\n\u002F\u002F\u002F use my_crate::parse_config;\n\u002F\u002F\u002F\n\u002F\u002F\u002F let config = parse_config(r#\"port = 8080\"#).unwrap();\n\u002F\u002F\u002F assert_eq!(config.port, 8080);\n\u002F\u002F\u002F ```\n\u002F\u002F\u002F\n\u002F\u002F\u002F ```no_run\n\u002F\u002F\u002F use my_crate::parse_config;\n\u002F\u002F\u002F\n\u002F\u002F\u002F assert!(parse_config(\"}{invalid\").is_err());\n\u002F\u002F\u002F ```\npub fn parse_config(input: &str) -> Result\u003CConfig, ParseError> {\n    todo!()\n}\n```\n\n## Benchmarking with Criterion\n\n```toml\n# Cargo.toml\n[dev-dependencies]\ncriterion = { version = \"0.5\", features = [\"html_reports\"] }\n\n[[bench]]\nname = \"benchmark\"\nharness = false\n```\n\n```rust\n\u002F\u002F benches\u002Fbenchmark.rs\nuse criterion::{black_box, criterion_group, criterion_main, Criterion};\n\nfn fibonacci(n: u64) -> u64 {\n    match n {\n        0 | 1 => n,\n        _ => fibonacci(n - 1) + fibonacci(n - 2),\n    }\n}\n\nfn bench_fibonacci(c: &mut Criterion) {\n    c.bench_function(\"fib 20\", |b| b.iter(|| fibonacci(black_box(20))));\n}\n\ncriterion_group!(benches, bench_fibonacci);\ncriterion_main!(benches);\n```\n\n## Test Coverage\n\n### Running Coverage\n\n```bash\n# Install: cargo install cargo-llvm-cov (or use taiki-e\u002Finstall-action in CI)\ncargo llvm-cov                    # Summary\ncargo llvm-cov --html             # HTML report\ncargo llvm-cov --lcov > lcov.info # LCOV format for CI\ncargo llvm-cov --fail-under-lines 80  # Fail if below threshold\n```\n\n### Coverage Targets\n\n| Code Type | Target |\n|-----------|--------|\n| Critical business logic | 100% |\n| Public API | 90%+ |\n| General code | 80%+ |\n| Generated \u002F FFI bindings | Exclude |\n\n## Testing Commands\n\n```bash\ncargo test                        # Run all tests\ncargo test -- --nocapture         # Show println output\ncargo test test_name              # Run tests matching pattern\ncargo test --lib                  # Unit tests only\ncargo test --test api_test        # Integration tests only\ncargo test --doc                  # Doc tests only\ncargo test --no-fail-fast         # Don't stop on first failure\ncargo test -- --ignored           # Run ignored tests\n```\n\n## Best Practices\n\n**DO:**\n- Write tests FIRST (TDD)\n- Use `#[cfg(test)]` modules for unit tests\n- Test behavior, not implementation\n- Use descriptive test names that explain the scenario\n- Prefer `assert_eq!` over `assert!` for better error messages\n- Use `?` in tests that return `Result` for cleaner error output\n- Keep tests independent — no shared mutable state\n\n**DON'T:**\n- Use `#[should_panic]` when you can test `Result::is_err()` instead\n- Mock everything — prefer integration tests when feasible\n- Ignore flaky tests — fix or quarantine them\n- Use `sleep()` in tests — use channels, barriers, or `tokio::time::pause()`\n- Skip error path testing\n\n## CI Integration\n\n```yaml\n# GitHub Actions\ntest:\n  runs-on: ubuntu-latest\n  steps:\n    - uses: actions\u002Fcheckout@v4\n    - uses: dtolnay\u002Frust-toolchain@stable\n      with:\n        components: clippy, rustfmt\n\n    - name: Check formatting\n      run: cargo fmt --check\n\n    - name: Clippy\n      run: cargo clippy -- -D warnings\n\n    - name: Run tests\n      run: cargo test\n\n    - uses: taiki-e\u002Finstall-action@cargo-llvm-cov\n\n    - name: Coverage\n      run: cargo llvm-cov --fail-under-lines 80\n```\n\n**Remember**: Tests are documentation. They show how your code is meant to be used. Write them clearly and keep them up to date.\n",{"name":5,"origin":24,"description":7},"ECC","main","481dcd7dd2e288b9d627a2bd017db70e64e6c6fa","core\u002Fskills\u002Frust-testing",2,"https:\u002F\u002Fgithub.com\u002FHoronomos-laps\u002FYana-AI","https:\u002F\u002Fyana.vutam.link\u002F","https:\u002F\u002Fgithub.com\u002FHoronomos-laps","https:\u002F\u002Fyana.vutam.link","An open-source governed runtime & execution environment for multi-agent AI systems.","2026-11-12 23:12:27",{"source":8,"skillName":5,"commands":36,"prompt":46,"zipAvailable":47},[37,40,43],{"tool":38,"command":39},"npx","npx skills add Horonomos-laps\u002FYana-AI --skill rust-testing",{"tool":41,"command":42},"bunx","bunx skills add Horonomos-laps\u002FYana-AI --skill rust-testing",{"tool":44,"command":45},"pnpm","pnpm dlx skills add Horonomos-laps\u002FYana-AI --skill rust-testing","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FHoronomos-laps\u002FYana-AI\u002Fblob\u002Fmain\u002Fcore\u002Fskills\u002Frust-testing\u002FSKILL.md",true,[],[50,58,65,73,81,89],{"skillNo":51,"name":52,"nameZh":6,"description":53,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":54,"licenseFileUrl":6,"sourceHtmlUrl":55,"categories":56,"keywords":57,"publishedAt":19},"01M735GKET5YVYKAY62W2P5YXB","openai--sentry--sentry","Use when the user asks to inspect Sentry issues or events, summarize recent production errors, or pull basic Sentry health data via the Sentry API; perform read-only queries with the bundled script and require `SENTRY_AUTH_TOKEN`.","MIT","https:\u002F\u002Fgithub.com\u002FHoronomos-laps\u002FYana-AI\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fopenai--sentry--sentry\u002FSKILL.md",[],[],{"skillNo":59,"name":60,"nameZh":6,"description":61,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":62,"categories":63,"keywords":64,"publishedAt":19},"01M73DCAP83T17HY7SMGK7MGFE","ito-basket-compare","Compare Itô prediction-market baskets against a user's knowledge base, portfolio notes, financial context, watchlist, or research thesis. Use for read-only basket comparison and gap analysis without investment advice or live trading.","https:\u002F\u002Fgithub.com\u002FHoronomos-laps\u002FYana-AI\u002Fblob\u002Fmain\u002Fcore\u002Fskills\u002Fito-basket-compare\u002FSKILL.md",[],[],{"skillNo":66,"name":67,"nameZh":6,"description":68,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":69,"sourceHtmlUrl":70,"categories":71,"keywords":72,"publishedAt":19},"01M734CYEMZFDR3KH6SW0JP8TD","implementing-network-traffic-baselining","Build network traffic baselines from NetFlow\u002FIPFIX data using Python pandas for statistical analysis, z-score anomaly detection, and hourly\u002Fdaily traffic pattern profiling","https:\u002F\u002Fgithub.com\u002Fyanacuti1121\u002FYana-AI\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fimplementing-network-traffic-baselining\u002FLICENSE","https:\u002F\u002Fgithub.com\u002FHoronomos-laps\u002FYana-AI\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fimplementing-network-traffic-baselining\u002FSKILL.md",[],[],{"skillNo":74,"name":75,"nameZh":6,"description":76,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":77,"sourceHtmlUrl":78,"categories":79,"keywords":80,"publishedAt":19},"01M73ASZ6NJRJM44Z2P84NGQ3Q","detecting-evasion-techniques-in-endpoint-logs","Detects defense evasion techniques used by adversaries in endpoint logs including log tampering, timestomping, process injection, and security tool disabling. Use when investigating suspicious endpoint behavior, building detection rules for evasion tactics, or conducting threat hunting for stealthy adversary activity. Activates for requests involving evasion detection, defense evasion analysis, log tampering detection, or MITRE ATT&CK TA0005.","https:\u002F\u002Fgithub.com\u002Fyanacuti1121\u002FYana-AI\u002Fblob\u002Fmain\u002Fcore\u002Fskills\u002Fdetecting-evasion-techniques-in-endpoint-logs\u002FLICENSE","https:\u002F\u002Fgithub.com\u002FHoronomos-laps\u002FYana-AI\u002Fblob\u002Fmain\u002Fcore\u002Fskills\u002Fdetecting-evasion-techniques-in-endpoint-logs\u002FSKILL.md",[],[],{"skillNo":82,"name":83,"nameZh":6,"description":84,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":85,"sourceHtmlUrl":86,"categories":87,"keywords":88,"publishedAt":19},"01M734AFNXD06Z78QRK0VKGT7Q","implementing-microsegmentation-with-guardicore","Implementing microsegmentation using Akamai Guardicore Segmentation to map application dependencies, create granular network policies, visualize east-west traffic flows, and enforce least-privilege communication between workloads across data centers and cloud.","https:\u002F\u002Fgithub.com\u002Fyanacuti1121\u002FYana-AI\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fimplementing-microsegmentation-with-guardicore\u002FLICENSE","https:\u002F\u002Fgithub.com\u002FHoronomos-laps\u002FYana-AI\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fimplementing-microsegmentation-with-guardicore\u002FSKILL.md",[],[],{"skillNo":90,"name":91,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":92,"categories":93,"keywords":94,"publishedAt":19},"01M736TK27QMCXK0DVCH25SJN5","ramdisk-tmpfs-patterns","https:\u002F\u002Fgithub.com\u002FHoronomos-laps\u002FYana-AI\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Framdisk-tmpfs-patterns\u002FSKILL.md",[],[]]