testing

GitHub

规范 Rust 项目测试编写与审查,涵盖单元测试、集成测试及 Fixtures 使用。强调行为断言、单场景测试及快速反馈,提供 Handler 测试模板与命名结构标准。

.agents/skills/testing/SKILL.md static-web-server/static-web-server

Trigger Scenarios

添加或修改 #[test] / #[tokio::test] 创建 tests/ 目录下的新文件或 fixtures 审查涉及测试覆盖率的 PR

Install

npx skills add static-web-server/static-web-server --skill testing -g -y
More Options

Non-standard path

npx skills add https://github.com/static-web-server/static-web-server/tree/master/.agents/skills/testing -g -y

Use without installing

npx skills use static-web-server/static-web-server@testing

指定 Agent (Claude Code)

npx skills add static-web-server/static-web-server --skill testing -a claude-code -g -y

安装 repo 全部 skill

npx skills add static-web-server/static-web-server --all -g -y

预览 repo 内 skill

npx skills add static-web-server/static-web-server --list

SKILL.md

Frontmatter
{
    "name": "testing",
    "description": "Write or review tests for the Static Web Server (SWS) project — unit tests, integration tests, test fixtures, and mocking strategies"
}

Testing Standards

Load this skill when writing, reviewing, or organizing tests — unit, integration, or fixture-based tests.

When to load: adding or editing any #[test] / #[tokio::test], creating a new file under tests/, adding fixtures under tests/fixtures/, or reviewing a PR that changes test coverage.

Testing Philosophy

  • Test behavior, not implementation: Assert on HTTP status codes, response headers, and body content — not internal state. If refactoring without changing behavior breaks a test, the test is wrong
  • One scenario per test: Each test verifies one request scenario. Multiple asserts are fine if they check the same logical outcome
  • Tests are documentation: A test name describes the expected behavior. compression_static_file_exists is better than test_compression_1
  • Fast feedback: Unit tests < 1ms. Integration tests < 100ms

Rust Testing

Unit Tests

  • Location: #[cfg(test)] mod tests { ... } at the bottom of each source file. SWS follows this convention throughout src/
  • Naming: fn feature_scenario_description()
  • Structure: Arrange (setup response/fixture) → Act (call function) → Assert (check headers, status, body)
  • Cover edge cases: Empty input, maximum input, invalid input, boundary values, unsupported methods
  • Use assert_eq! and assert!: Prefer specific assertions over raw assert!

Integration Tests

  • Location: tests/ directory at the crate root
  • Scope: Each file tests one user-visible feature (e.g., tests/compression.rs, tests/cors.rs, tests/dir_listing.rs)
  • Test against real file fixtures: Use tests/fixtures/public/ for test files. Add new fixtures when testing new scenarios
  • Use the fixture infrastructure: Import from static_web_server::testing::fixtures:
    • fixture_settings("toml/handler_fixtures.toml") — load TOML config
    • fixture_req_handler_opts(general, advanced) — build handler options
    • fixture_req_handler(opts) — create a request handler
  • Test with different HTTP methods: Loop over GET, HEAD, OPTIONS and assert correct behavior per method

Handler Tests

SWS's most common test pattern: create a handler, send a synthetic request, assert on the response:

use std::net::SocketAddr;
use hyper::{Method, Request, header::ACCEPT_ENCODING};
use static_web_server::testing::fixtures::*;
use static_web_server::settings::cli::General;

#[tokio::test]
async fn compression_static_file_exists() {
    let opts = fixture_settings("toml/handler_fixtures.toml");
    let general = General {
        compression_static: true,
        ..opts.general
    };
    let req_handler_opts = fixture_req_handler_opts(general, opts.advanced);
    let req_handler = fixture_req_handler(req_handler_opts);
    let remote_addr: Option<SocketAddr> = Some(REMOTE_ADDR.parse().unwrap());

    let mut req = Request::new(());
    *req.method_mut() = Method::GET;
    *req.uri_mut() = "http://localhost/index.htm".parse().unwrap();
    req.headers_mut().insert(ACCEPT_ENCODING, "gzip, deflate, br".parse().unwrap());

    match req_handler.handle(&mut req, remote_addr).await {
        Ok(res) => {
            assert_eq!(res.status(), 200);
            assert_eq!(res.headers()["content-encoding"], "br");
            assert_eq!(res.headers()["vary"], "accept-encoding");
        }
        Err(err) => panic!("unexpected error: {err}"),
    }
}

REMOTE_ADDR ("127.0.0.1:1234") is exported from static_web_server::testing::fixtures.

Static File Tests

Tests in tests/static_files.rs call static_files::handle() directly with a HandleOpts struct. This tests the file-serving logic in isolation (without the full handler pipeline):

let result = static_files::handle(&HandleOpts {
    method: &Method::GET,
    headers: &HeaderMap::new(),
    base_path: &root_dir(),
    uri_path: "index.htm",
    index_files: &["index.htm"],
    // ... other opts
}).await;

Cleaning Up

Integration tests using pre-existing fixtures under tests/fixtures/ are read-only and need no cleanup. If a test creates temporary files (e.g., a temp upload directory), clean them up in a Drop handler or #[tokio::test] teardown step.

Test Fixture Organization

tests/
  fixtures/
    public/           # Default test file tree
      index.html
      404.html
      assets/
        main.css
        main.css.zst  # Pre-compressed variant for static compression tests
    compression/       # Compression-specific test fixtures
    markdown/          # Markdown content-negotiation test fixtures
    toml/              # TOML config files for handler tests
    tls/               # TLS certificate/key test fixtures

What to Test

  • Always test: Public API surface, error cases, edge cases, HTTP status codes, response headers, supported/unsupported methods
  • Sometimes test: Private functions with branching logic (3+ code paths) or performance-critical code (include benchmarks for the latter)
  • Don't test: Trivial getters/setters, framework glue code, exact log message strings

Run Commands

# Run all tests with all features
RUSTFLAGS="--cfg tokio_unstable" cargo test --tests --features="all"

# Run a specific test
cargo test --test compression -- compression_static_file_exists

# Run with trace logging visible
RUST_LOG=trace cargo test --test static_files -- --nocapture

Checklist

  • Do tests cover the happy path and at least one error path?
  • Do integration tests clean up after themselves?
  • Are test names descriptive?
  • Are mocks used only for external dependencies (network), while filesystem access uses real test fixtures?
  • Are test fixtures minimal (synthetic, small files)?

Version History

  • 21dc11b Current 2026-08-20 17:42

Same Skill Collection

.agents/skills/code-quality/SKILL.md
.agents/skills/design/SKILL.md
.agents/skills/issue-tracking/SKILL.md
.agents/skills/performance/SKILL.md
.agents/skills/prose/SKILL.md
.agents/skills/rust-backend/SKILL.md
.agents/skills/security/SKILL.md
.agents/skills/static-file-serving/SKILL.md

Metadata

Files
0
Version
4ec71ce
Hash
186a5e52
Indexed
2026-08-20 17:42

Accueil - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-30 20:49
浙ICP备14020137号-1 $Carte des visiteurs$