Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/tomevault-io/skills-registry --skill rust-testing명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
| Use when this capability is needed.
> Use when this capability is needed.
Review architecture and API design for the vfs-s3 project. Use when the user mentions @architect, asks to review an issue's design, discuss module boundaries, API shape, or architectural decisions for vfs-s3. Also trigger when the user wants to create an ADR (Architecture Decision Record) or evaluate a technical approach for the project. Intended for dispatch from Codex automation or Claude routines; GitHub trigger phrase: @vfs-s3-bot please prepare design doc Use when this capability is needed.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | rust-testing |
| description | | Use when this capability is needed. |
Testing in Rust is first-class: cargo test runs unit + integration tests, doctests are auto-run, and the ecosystem has excellent tools for every testing need.
// Unit tests: in the same file as the code they test
// src/user.rs
pub fn validate_age(age: u32) -> bool {
age >= 0 && age <= 150
}
#[cfg(test)] // Only compiled when running tests
mod tests {
use super::*; // Access private functions
#[test]
fn valid_age_returns_true() {
assert!(validate_age(25));
}
#[test]
fn age_zero_is_valid() {
assert!(validate_age(0));
}
#[test]
fn age_over_150_is_invalid() {
assert!(!validate_age(151));
}
}
// Integration tests: in tests/ directory (public API only)
tests/
├── integration_test.rs
└── common/
└── mod.rs // Shared test helpers
// tests/integration_test.rs
use my_lib::UserService;
mod common; // tests/common/mod.rs
#[test]
fn create_and_find_user() {
let db = common::setup_test_db();
let svc = UserService::new(db);
let user = svc.create("Alice", "alice@example.com").unwrap();
let found = svc.find(user.id).unwrap();
assert_eq!(found.name, "Alice");
}
Use descriptive names that read like specifications:
// Bad: no context
#[test] fn test1() {}
#[test] fn test_process() {}
// Good: <what>_<when/given>_<expected result>
#[test] fn validate_email_with_missing_at_sign_returns_error() {}
#[test] fn transfer_funds_when_balance_insufficient_returns_insufficient_funds_error() {}
#[test] fn parse_config_with_missing_required_field_fails() {}
// Basic
assert!(condition);
assert_eq!(left, right);
assert_ne!(left, right);
// With messages
assert!(user.is_active(), "Expected user {id} to be active");
assert_eq!(result, expected, "Processing {input} failed");
// Approximate equality for floats
assert!((result - 3.14159).abs() < 1e-5);
// Pattern matching
assert!(matches!(result, Ok(User { name, .. }) if name == "Alice"));
// Panics assertion
#[test]
#[should_panic(expected = "out of bounds")]
fn access_out_of_bounds_panics() {
let v = vec![1, 2, 3];
let _ = v[10];
}
#[test]
fn deduct_items_from_inventory_reduces_stock() {
// Arrange
let mut inventory = Inventory::new();
inventory.add_stock("widget", 10);
// Act
let result = inventory.deduct("widget", 3);
// Assert
assert!(result.is_ok());
assert_eq!(inventory.stock("widget"), 7);
}
// Test async functions with tokio
#[tokio::test]
async fn fetch_user_returns_correct_data() {
let client = TestClient::new();
let user = client.get_user(42).await.unwrap();
assert_eq!(user.id, 42);
}
// Single-threaded async test (faster, no thread synchronization)
#[tokio::test(flavor = "current_thread")]
async fn concurrent_tasks_complete() {
let (r1, r2) = tokio::join!(task_one(), task_two());
assert!(r1.is_ok());
assert!(r2.is_ok());
}
// Test with timeout
#[tokio::test]
async fn operation_completes_within_timeout() {
let result = tokio::time::timeout(
std::time::Duration::from_secs(1),
some_async_operation(),
)
.await;
assert!(result.is_ok(), "Operation timed out");
}
// Reusable test data builders
struct UserBuilder {
name: String,
email: String,
age: u32,
}
impl Default for UserBuilder {
fn default() -> Self {
Self {
name: "Test User".into(),
email: "test@example.com".into(),
age: 25,
}
}
}
impl UserBuilder {
fn name(mut self, name: &str) -> Self { self.name = name.into(); self }
fn email(mut self, email: &str) -> Self { self.email = email.into(); self }
fn build(self) -> User {
User::new(self.name, self.email, self.age).unwrap()
}
}
() {
= UserBuilder::()
.()
.()
.();
}
// RAII fixture — cleanup runs automatically
struct TempDatabase {
path: std::path::PathBuf,
conn: DbConnection,
}
impl TempDatabase {
fn new() -> Self {
let path = std::env::temp_dir()
.join(format!("test-db-{}.db", uuid::Uuid::new_v4()));
let conn = DbConnection::create(&path).unwrap();
conn.run_migrations().unwrap();
Self { path, conn }
}
}
impl Drop for TempDatabase {
fn drop(&mut self) {
let _ = std::fs::remove_file(&self.path);
}
}
#[test]
fn user_created_in_database() {
let db = TempDatabase::new(); // Created
db.conn.insert_user("Alice").unwrap();
assert_eq!(db.conn.count_users().(), );
}
use mockall::automock;
#[automock]
trait EmailService: Send + Sync {
fn send(&self, to: &str, subject: &str, body: &str) -> Result<(), EmailError>;
}
#[test]
fn password_reset_sends_email() {
let mut mock_email = MockEmailService::new();
// Set expectation: send() called once with specific args
mock_email
.expect_send()
.with(
mockall::predicate::eq("user@example.com"),
mockall::predicate::str::contains("Reset"),
mockall::predicate::always(),
)
.times(1)
.returning(|_, _, _| Ok(()));
let service = PasswordService::new(Arc::new(mock_email));
service.send_reset_link("user@example.com").unwrap();
// Mock verifies expectations on drop
}
use proptest::prelude::*;
// Property: encode then decode is identity
proptest! {
#[test]
fn encode_decode_roundtrip(original in ".*") {
let encoded = base64_encode(&original);
let decoded = base64_decode(&encoded).unwrap();
prop_assert_eq!(original, decoded);
}
#[test]
fn sort_is_idempotent(mut v in prop::collection::vec(any::<i32>(), 0..100)) {
v.sort();
let once_sorted = v.clone();
v.sort();
prop_assert_eq!(v, once_sorted);
}
#[test]
fn add_is_commutative(a in 0i32..1000, b in 0i32..1000) {
prop_assert_eq!(a + b, b + a);
}
}
// Custom strategies
fn valid_email() -> impl Strategy<Value = String> {
r"[a-z]{3,10}@[a-z]{3,10}\.[a-z]{2,4}".prop_map(|s| s)
}
proptest! {
(email ()) {
prop_assert!(Email::(&email).());
}
}
use insta::assert_snapshot;
#[test]
fn render_user_profile() {
let user = User { name: "Alice".into(), role: Role::Admin, age: 30 };
let rendered = render_profile(&user);
// First run: creates snapshot file
// Subsequent runs: compares against saved snapshot
assert_snapshot!(rendered);
}
// JSON snapshots
use insta::assert_json_snapshot;
#[test]
fn api_response_matches_snapshot() {
let response = api_client.get_user(1).unwrap();
assert_json_snapshot!(response, {
".created_at" => "[timestamp]", // Redact dynamic fields
".id" => "[id]",
});
}
# Review and accept new/changed snapshots
cargo install cargo-insta
cargo insta review
[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
[[bench]]
name = "my_bench"
harness = false
// benches/my_bench.rs
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
fn fibonacci(n: u64) -> u64 {
match n {
0 | 1 => n,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
fn bench_fibonacci(c: &mut Criterion) {
let mut group = c.benchmark_group("fibonacci");
for size in [10u64, 20, 30] {
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
b.iter(|| fibonacci(black_box(size)));
});
}
group.finish();
}
// Compare implementations
fn bench_string_ops(c: &mut Criterion) {
let mut group = c.benchmark_group("string_creation");
let s = "hello world";
group.bench_function(, |b| b.(|| (s).()));
group.(, |b| b.(|| (s).()));
group.(, |b| b.(|| ::((s))));
group.();
}
criterion_group!(benches, bench_fibonacci, bench_string_ops);
criterion_main!(benches);
cargo bench # Run all benchmarks
cargo bench -- "fibonacci" # Run matching benchmarks
cargo bench -- --save-baseline main # Save baseline
cargo bench -- --baseline main # Compare to baseline
/// Parses a version string into components.
///
/// # Examples
///
/// ```
/// use mylib::parse_version;
///
/// let (major, minor, patch) = parse_version("1.2.3").unwrap();
/// assert_eq!(major, 1);
/// assert_eq!(minor, 2);
/// assert_eq!(patch, 3);
/// ```
///
/// Returns `None` for invalid version strings:
///
/// ```
/// use mylib::parse_version;
/// assert!(parse_version("not-a-version").is_none());
/// ```
pub fn parse_version(s: &str) -> Option<(u32, u32, u32)> {
// ...
}
cargo test --doc # Run only doctests
Always split your test blocks visually into three distinct phases for maximum readability:
#[test]
fn withdraw_reduces_account_balance() {
// Arrange
let mut account = Account::new(dec!(100.00));
let amount = dec!(40.00);
// Act
account.withdraw(amount).unwrap();
// Assert
assert_eq!(account.balance(), dec!(60.00));
}
Use structs implementing the Drop trait to handle setup and cleanup actions, ensuring database connections, file handles, or mock servers are torn down even if the test panics.
struct TestDbFixture {
pub conn_str: String,
}
impl TestDbFixture {
fn new() -> Self {
let conn_str = format!("test_db_{}", uuid::Uuid::new_v4());
// Initialize test database...
Self { conn_str }
}
}
impl Drop for TestDbFixture {
fn drop(&mut self) {
// Tear down test database...
}
}
#[test]
fn query_returns_inserted_record() {
let fixture = TestDbFixture::new();
// database operations using fixture.conn_str ...
// automatically dropped at scope exit
}
cargo test # All tests
cargo test user # Tests with "user" in name
cargo test -- --nocapture # Show println! output
cargo test -- --test-threads=1 # Single-threaded (for shared state tests)
cargo test --lib # Unit tests only
cargo test --test integration_test # Specific integration test file
cargo test --doc # Doctests only
cargo test --release # Tests in release mode
cargo install cargo-tarpaulin # Linux/macOS
cargo tarpaulin --out Html --output-dir coverage/
# Or with llvm-cov (cross-platform)
cargo install cargo-llvm-cov
cargo llvm-cov --html
tests/ integration tests.Source: adxptived/Rust-Skills — distributed by TomeVault.