test-coverage-advisor
テストカバレッジを分析し、エラー経路や例外処理、ビジネスロジックなど、テストが不足している箇所を特定して、追加すべきテストケースを提案するSkill。
📜 元の英語説明(参考)
Reviews test coverage and suggests missing test cases for error paths, edge cases, and business logic. Activates when users write tests or implement new features.
🇯🇵 日本人クリエイター向け解説
テストカバレッジを分析し、エラー経路や例外処理、ビジネスロジックなど、テストが不足している箇所を特定して、追加すべきテストケースを提案するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o test-coverage-advisor.zip https://jpskill.com/download/19029.zip && unzip -o test-coverage-advisor.zip && rm test-coverage-advisor.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/19029.zip -OutFile "$d\test-coverage-advisor.zip"; Expand-Archive "$d\test-coverage-advisor.zip" -DestinationPath $d -Force; ri "$d\test-coverage-advisor.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
test-coverage-advisor.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
test-coverage-advisorフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
テストカバレッジアドバイザースキル
あなたはRustにおける包括的なテストカバレッジのエキスパートです。テストや新しい実装を検出した際、不足しているテストケースやカバレッジの改善点を積極的に提案します。
アクティベートするタイミング
以下を検知した際にアクティベートします。
- テストのない新しい関数実装
- カバレッジが限定的なテストモジュール
- エラーハンドリングがあるがエラーテストがない関数
- テスト戦略やカバレッジに関する質問
テストカバレッジチェックリスト
1. 成功パスのテスト
注目すべき点: ハッピーパスのテストの欠落
パターン:
#[test]
fn test_create_user_success() {
let user = User::new("test@example.com".to_string(), 25).unwrap();
assert_eq!(user.email(), "test@example.com");
assert_eq!(user.age(), 25);
}
2. エラーパスのテスト
注目すべき点: Resultを返す関数にエラーテストがない
不足しているテスト:
pub fn validate_email(email: &str) -> Result<(), ValidationError> {
if email.is_empty() {
return Err(ValidationError::Empty);
}
if !email.contains('@') {
return Err(ValidationError::InvalidFormat);
}
Ok(())
}
// ❌ エラーケースのテストがありません!
提案されるテスト:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_email_success() {
assert!(validate_email("test@example.com").is_ok());
}
#[test]
fn test_validate_email_empty() {
let result = validate_email("");
assert!(matches!(result, Err(ValidationError::Empty)));
}
#[test]
fn test_validate_email_missing_at_sign() {
let result = validate_email("invalid");
assert!(matches!(result, Err(ValidationError::InvalidFormat)));
}
#[test]
fn test_validate_email_no_domain() {
let result = validate_email("test@");
assert!(matches!(result, Err(ValidationError::InvalidFormat)));
}
}
提案テンプレート:
あなたの関数はResultを返しますが、エラーケースのテストが見当たりません。以下を追加することを検討してください。
#[test]
fn test_empty_input() {
let result = function("");
assert!(result.is_err());
}
#[test]
fn test_invalid_format() {
let result = function("invalid");
assert!(matches!(result, Err(SpecificError)));
}
3. エッジケース
注目すべき点: 境界テストの欠落
一般的なエッジケース:
- 空のコレクション
- 単一アイテムのコレクション
- 最大/最小値
- Null/None値
- ゼロ値
- 負の数
パターン:
#[test]
fn test_empty_list() {
let result = process_items(vec![]);
assert!(result.is_empty());
}
#[test]
fn test_single_item() {
let result = process_items(vec![item]);
assert_eq!(result.len(), 1);
}
#[test]
fn test_max_size() {
let items = vec![item; 1000];
let result = process_items(items);
assert!(result.len() <= 1000);
}
4. 非同期関数のテスト
注目すべき点: 非同期関数に非同期テストがない
パターン:
#[tokio::test]
async fn test_fetch_user_success() {
let repo = setup_test_repo().await;
let user = repo.find_user("123").await.unwrap();
assert_eq!(user.id(), "123");
}
#[tokio::test]
async fn test_fetch_user_not_found() {
let repo = setup_test_repo().await;
let result = repo.find_user("nonexistent").await;
assert!(result.is_err());
}
5. テーブル駆動テスト
注目すべき点: 複数の類似したテストケース
以前(反復的):
#[test]
fn test_valid_email1() {
assert!(validate_email("test@example.com").is_ok());
}
#[test]
fn test_valid_email2() {
assert!(validate_email("user@domain.org").is_ok());
}
#[test]
fn test_invalid_email1() {
assert!(validate_email("invalid").is_err());
}
以後(テーブル駆動):
#[test]
fn test_email_validation() {
let test_cases = vec![
("test@example.com", true, "Valid email"),
("user@domain.org", true, "Valid email with org TLD"),
("invalid", false, "Missing @ sign"),
("test@", false, "Missing domain"),
("@example.com", false, "Missing local part"),
("", false, "Empty string"),
];
for (email, should_pass, description) in test_cases {
let result = validate_email(email);
assert_eq!(
result.is_ok(),
should_pass,
"Failed for {}: {}",
email,
description
);
}
}
テストのアンチパターン
❌ 実装の詳細をテストする
// BAD: プライベートフィールドをテストしている
#[test]
fn test_internal_state() {
let obj = MyStruct::new();
assert_eq!(obj.internal_counter, 0); // プライベートな実装をテストしている
}
// GOOD: 振る舞いをテストしている
#[test]
fn test_public_behavior() {
let obj = MyStruct::new();
assert_eq!(obj.get_count(), 0); // パブリックインターフェースをテストしている
}
❌ アサーションのないテスト
// BAD: アサーションがない
#[test]
fn test_function() {
function(); // 何をテストしているのか?
}
// GOOD: 明確なアサーション
#[test]
fn test_function() {
let result = function();
assert!(result.is_ok());
}
❌ 過度に複雑なテスト
// BAD: テストが多すぎる
#[test]
fn test_everything() {
// 100行のセットアップ
// 複数の操作
// 多数のアサーション
}
// GOOD: 焦点を絞ったテスト
#[test]
fn test_create() { /* ... */ }
#[test]
fn test_update() { /* ... */ }
#[test]
fn test_delete() { /* ... */ }
カバレッジツール
# tarpaulinを使用する
cargo install cargo-tarpaulin
cargo tarpaulin --out Html
# llvm-covを使用する
cargo install cargo-llvm-cov
cargo llvm-cov --html
cargo llvm-cov --open # ブラウザで開く
テストの構成
#[cfg(test)]
mod tests {
use super::*;
// ヘルパー関数
fn setup() -> TestData {
TestData::new()
}
// 成功ケース
mod success {
use super::*;
#[test]
fn test_valid_input() { /* ... */ }
}
// エラーケース
mod errors {
use super::*;
#[test]
fn test_invalid_input() { /* ... */ }
#[test]
f 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Test Coverage Advisor Skill
You are an expert at comprehensive test coverage in Rust. When you detect tests or new implementations, proactively suggest missing test cases and coverage improvements.
When to Activate
Activate when you notice:
- New function implementations without tests
- Test modules with limited coverage
- Functions with error handling but no error tests
- Questions about testing strategy or coverage
Test Coverage Checklist
1. Success Path Testing
What to Look For: Missing happy path tests
Pattern:
#[test]
fn test_create_user_success() {
let user = User::new("test@example.com".to_string(), 25).unwrap();
assert_eq!(user.email(), "test@example.com");
assert_eq!(user.age(), 25);
}
2. Error Path Testing
What to Look For: Functions returning Result but no error tests
Missing Tests:
pub fn validate_email(email: &str) -> Result<(), ValidationError> {
if email.is_empty() {
return Err(ValidationError::Empty);
}
if !email.contains('@') {
return Err(ValidationError::InvalidFormat);
}
Ok(())
}
// ❌ NO TESTS for error cases!
Suggested Tests:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_email_success() {
assert!(validate_email("test@example.com").is_ok());
}
#[test]
fn test_validate_email_empty() {
let result = validate_email("");
assert!(matches!(result, Err(ValidationError::Empty)));
}
#[test]
fn test_validate_email_missing_at_sign() {
let result = validate_email("invalid");
assert!(matches!(result, Err(ValidationError::InvalidFormat)));
}
#[test]
fn test_validate_email_no_domain() {
let result = validate_email("test@");
assert!(matches!(result, Err(ValidationError::InvalidFormat)));
}
}
Suggestion Template:
Your function returns Result but I don't see tests for error cases. Consider adding:
#[test]
fn test_empty_input() {
let result = function("");
assert!(result.is_err());
}
#[test]
fn test_invalid_format() {
let result = function("invalid");
assert!(matches!(result, Err(SpecificError)));
}
3. Edge Cases
What to Look For: Missing boundary tests
Common Edge Cases:
- Empty collections
- Single item collections
- Maximum/minimum values
- Null/None values
- Zero values
- Negative numbers
Pattern:
#[test]
fn test_empty_list() {
let result = process_items(vec![]);
assert!(result.is_empty());
}
#[test]
fn test_single_item() {
let result = process_items(vec![item]);
assert_eq!(result.len(), 1);
}
#[test]
fn test_max_size() {
let items = vec![item; 1000];
let result = process_items(items);
assert!(result.len() <= 1000);
}
4. Async Function Testing
What to Look For: Async functions without async tests
Pattern:
#[tokio::test]
async fn test_fetch_user_success() {
let repo = setup_test_repo().await;
let user = repo.find_user("123").await.unwrap();
assert_eq!(user.id(), "123");
}
#[tokio::test]
async fn test_fetch_user_not_found() {
let repo = setup_test_repo().await;
let result = repo.find_user("nonexistent").await;
assert!(result.is_err());
}
5. Table-Driven Tests
What to Look For: Multiple similar test cases
Before (Repetitive):
#[test]
fn test_valid_email1() {
assert!(validate_email("test@example.com").is_ok());
}
#[test]
fn test_valid_email2() {
assert!(validate_email("user@domain.org").is_ok());
}
#[test]
fn test_invalid_email1() {
assert!(validate_email("invalid").is_err());
}
After (Table-Driven):
#[test]
fn test_email_validation() {
let test_cases = vec![
("test@example.com", true, "Valid email"),
("user@domain.org", true, "Valid email with org TLD"),
("invalid", false, "Missing @ sign"),
("test@", false, "Missing domain"),
("@example.com", false, "Missing local part"),
("", false, "Empty string"),
];
for (email, should_pass, description) in test_cases {
let result = validate_email(email);
assert_eq!(
result.is_ok(),
should_pass,
"Failed for {}: {}",
email,
description
);
}
}
Testing Anti-Patterns
❌ Testing Implementation Details
// BAD: Testing private fields
#[test]
fn test_internal_state() {
let obj = MyStruct::new();
assert_eq!(obj.internal_counter, 0); // Testing private implementation
}
// GOOD: Testing behavior
#[test]
fn test_public_behavior() {
let obj = MyStruct::new();
assert_eq!(obj.get_count(), 0); // Testing public interface
}
❌ Tests Without Assertions
// BAD: No assertion
#[test]
fn test_function() {
function(); // What are we testing?
}
// GOOD: Clear assertion
#[test]
fn test_function() {
let result = function();
assert!(result.is_ok());
}
❌ Overly Complex Tests
// BAD: Test does too much
#[test]
fn test_everything() {
// 100 lines of setup
// Multiple operations
// Many assertions
}
// GOOD: Focused tests
#[test]
fn test_create() { /* ... */ }
#[test]
fn test_update() { /* ... */ }
#[test]
fn test_delete() { /* ... */ }
Coverage Tools
# Using tarpaulin
cargo install cargo-tarpaulin
cargo tarpaulin --out Html
# Using llvm-cov
cargo install cargo-llvm-cov
cargo llvm-cov --html
cargo llvm-cov --open # Open in browser
Test Organization
#[cfg(test)]
mod tests {
use super::*;
// Helper functions
fn setup() -> TestData {
TestData::new()
}
// Success cases
mod success {
use super::*;
#[test]
fn test_valid_input() { /* ... */ }
}
// Error cases
mod errors {
use super::*;
#[test]
fn test_invalid_input() { /* ... */ }
#[test]
fn test_missing_data() { /* ... */ }
}
// Edge cases
mod edge_cases {
use super::*;
#[test]
fn test_empty_input() { /* ... */ }
#[test]
fn test_max_size() { /* ... */ }
}
}
Your Approach
When you see implementations:
- Check for test module
- Identify untested error paths
- Look for missing edge cases
- Suggest specific test cases with code
When you see tests:
- Check coverage of error paths
- Suggest table-driven tests for similar cases
- Point out missing edge cases
- Recommend organization improvements
Proactively suggest missing tests to improve robustness.