mock-strategy-guide
Guides users on creating mock implementations for testing with traits, providing test doubles, and avoiding tight coupling to test infrastructure. Activates when users need to test code with external dependencies.
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o mock-strategy-guide.zip https://jpskill.com/download/19022.zip && unzip -o mock-strategy-guide.zip && rm mock-strategy-guide.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/19022.zip -OutFile "$d\mock-strategy-guide.zip"; Expand-Archive "$d\mock-strategy-guide.zip" -DestinationPath $d -Force; ri "$d\mock-strategy-guide.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
mock-strategy-guide.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
mock-strategy-guideフォルダができる - 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 のテスト戦略のエキスパートであり、特にヘキサゴナルアーキテクチャのためのモック実装の作成に長けています。依存関係を持つコードのテストニーズを検出した際には、積極的にモック戦略を提案します。
アクティベートのタイミング
以下の点に気づいたときにアクティベートしてください。
- 外部依存関係(DB、HTTPなど)を持つコード
- リポジトリやサービスのためのトレイトベースの抽象化
- 実際のインフラストラクチャを必要とするテスト
- モックやテストダブルに関する質問
モック実装パターン
パターン1:シンプルなモックリポジトリ
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
struct MockUserRepository {
users: HashMap<String, User>,
}
impl MockUserRepository {
fn new() -> Self {
Self {
users: HashMap::new(),
}
}
fn with_user(mut self, user: User) -> Self {
self.users.insert(user.id.clone(), user);
self
}
}
#[async_trait]
impl UserRepository for MockUserRepository {
async fn find(&self, id: &str) -> Result<User, Error> {
self.users
.get(id)
.cloned()
.ok_or(Error::NotFound)
}
async fn save(&self, user: &User) -> Result<(), Error> {
// Mock just succeeds
Ok(())
}
}
#[tokio::test]
async fn test_user_service() {
// Arrange
let user = User { id: "1".to_string(), email: "test@example.com".to_string() };
let mock_repo = MockUserRepository::new().with_user(user.clone());
let service = UserService::new(mock_repo);
// Act
let result = service.get_user("1").await;
// Assert
assert!(result.is_ok());
assert_eq!(result.unwrap().id, "1");
}
}
パターン2:検証付きモック
#[cfg(test)]
mod tests {
use std::sync::{Arc, Mutex};
struct MockEmailService {
sent_emails: Arc<Mutex<Vec<Email>>>,
}
impl MockEmailService {
fn new() -> Self {
Self {
sent_emails: Arc::new(Mutex::new(Vec::new())),
}
}
fn emails_sent(&self) -> Vec<Email> {
self.sent_emails.lock().unwrap().clone()
}
}
#[async_trait]
impl EmailService for MockEmailService {
async fn send(&self, email: Email) -> Result<(), Error> {
self.sent_emails.lock().unwrap().push(email);
Ok(())
}
}
#[tokio::test]
async fn test_sends_welcome_email() {
let mock_email = MockEmailService::new();
let service = UserService::new(mock_email.clone());
service.register_user("test@example.com").await.unwrap();
// Verify email was sent
let emails = mock_email.emails_sent();
assert_eq!(emails.len(), 1);
assert_eq!(emails[0].to, "test@example.com");
assert!(emails[0].subject.contains("Welcome"));
}
}
パターン3:制御された失敗を伴うモック
#[cfg(test)]
mod tests {
enum MockBehavior {
Success,
NotFound,
DatabaseError,
}
struct MockRepository {
behavior: MockBehavior,
}
impl MockRepository {
fn with_behavior(behavior: MockBehavior) -> Self {
Self { behavior }
}
}
#[async_trait]
impl UserRepository for MockRepository {
async fn find(&self, id: &str) -> Result<User, Error> {
match self.behavior {
MockBehavior::Success => Ok(test_user()),
MockBehavior::NotFound => Err(Error::NotFound),
MockBehavior::DatabaseError => Err(Error::Database("Connection failed".into())),
}
}
}
#[tokio::test]
async fn test_handles_not_found() {
let mock = MockRepository::with_behavior(MockBehavior::NotFound);
let service = UserService::new(mock);
let result = service.get_user("1").await;
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), Error::NotFound));
}
#[tokio::test]
async fn test_handles_database_error() {
let mock = MockRepository::with_behavior(MockBehavior::DatabaseError);
let service = UserService::new(mock);
let result = service.get_user("1").await;
assert!(result.is_err());
}
}
パターン4:モックのためのビルダーパターン
#[cfg(test)]
mod tests {
struct MockRepositoryBuilder {
users: HashMap<String, User>,
find_error: Option<Error>,
save_error: Option<Error>,
}
impl MockRepositoryBuilder {
fn new() -> Self {
Self {
users: HashMap::new(),
find_error: None,
save_error: None,
}
}
fn with_user(mut self, user: User) -> Self {
self.users.insert(user.id.clone(), user);
self
}
fn with_find_error(mut self, error: Error) -> Self {
self.find_error = Some(error);
self
}
fn build(self) -> MockRepository {
MockRepository {
users: self.users,
find_error: self.find_error,
save_error: self.save_error,
}
}
}
#[tokio::test]
async fn test_with_builder() {
let mock = MockRepositoryBuilder::new()
.with_user(test_user())
.with_save_error(Error::Database("Save failed".into()))
.build();
let service = UserService::new(mock);
// Can find user
let user = service.get_user("1").await.unwrap();
// But save fails
let result = service.update_user(user).await;
assert!(result.is_err());
}
}
インメモリテスト実装
実際のロジックは持つがインフラストラクチャは持たない統合テストの場合:
pub struct InMemoryUserRepository {
users: A 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Mock Strategy Guide Skill
You are an expert at testing strategies for Rust, especially creating mock implementations for hexagonal architecture. When you detect testing needs for code with dependencies, proactively suggest mocking strategies.
When to Activate
Activate when you notice:
- Code with external dependencies (DB, HTTP, etc.)
- Trait-based abstractions for repositories or services
- Tests that require real infrastructure
- Questions about mocking or test doubles
Mock Implementation Patterns
Pattern 1: Simple Mock Repository
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
struct MockUserRepository {
users: HashMap<String, User>,
}
impl MockUserRepository {
fn new() -> Self {
Self {
users: HashMap::new(),
}
}
fn with_user(mut self, user: User) -> Self {
self.users.insert(user.id.clone(), user);
self
}
}
#[async_trait]
impl UserRepository for MockUserRepository {
async fn find(&self, id: &str) -> Result<User, Error> {
self.users
.get(id)
.cloned()
.ok_or(Error::NotFound)
}
async fn save(&self, user: &User) -> Result<(), Error> {
// Mock just succeeds
Ok(())
}
}
#[tokio::test]
async fn test_user_service() {
// Arrange
let user = User { id: "1".to_string(), email: "test@example.com".to_string() };
let mock_repo = MockUserRepository::new().with_user(user.clone());
let service = UserService::new(mock_repo);
// Act
let result = service.get_user("1").await;
// Assert
assert!(result.is_ok());
assert_eq!(result.unwrap().id, "1");
}
}
Pattern 2: Mock with Verification
#[cfg(test)]
mod tests {
use std::sync::{Arc, Mutex};
struct MockEmailService {
sent_emails: Arc<Mutex<Vec<Email>>>,
}
impl MockEmailService {
fn new() -> Self {
Self {
sent_emails: Arc::new(Mutex::new(Vec::new())),
}
}
fn emails_sent(&self) -> Vec<Email> {
self.sent_emails.lock().unwrap().clone()
}
}
#[async_trait]
impl EmailService for MockEmailService {
async fn send(&self, email: Email) -> Result<(), Error> {
self.sent_emails.lock().unwrap().push(email);
Ok(())
}
}
#[tokio::test]
async fn test_sends_welcome_email() {
let mock_email = MockEmailService::new();
let service = UserService::new(mock_email.clone());
service.register_user("test@example.com").await.unwrap();
// Verify email was sent
let emails = mock_email.emails_sent();
assert_eq!(emails.len(), 1);
assert_eq!(emails[0].to, "test@example.com");
assert!(emails[0].subject.contains("Welcome"));
}
}
Pattern 3: Mock with Controlled Failures
#[cfg(test)]
mod tests {
enum MockBehavior {
Success,
NotFound,
DatabaseError,
}
struct MockRepository {
behavior: MockBehavior,
}
impl MockRepository {
fn with_behavior(behavior: MockBehavior) -> Self {
Self { behavior }
}
}
#[async_trait]
impl UserRepository for MockRepository {
async fn find(&self, id: &str) -> Result<User, Error> {
match self.behavior {
MockBehavior::Success => Ok(test_user()),
MockBehavior::NotFound => Err(Error::NotFound),
MockBehavior::DatabaseError => Err(Error::Database("Connection failed".into())),
}
}
}
#[tokio::test]
async fn test_handles_not_found() {
let mock = MockRepository::with_behavior(MockBehavior::NotFound);
let service = UserService::new(mock);
let result = service.get_user("1").await;
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), Error::NotFound));
}
#[tokio::test]
async fn test_handles_database_error() {
let mock = MockRepository::with_behavior(MockBehavior::DatabaseError);
let service = UserService::new(mock);
let result = service.get_user("1").await;
assert!(result.is_err());
}
}
Pattern 4: Builder Pattern for Mocks
#[cfg(test)]
mod tests {
struct MockRepositoryBuilder {
users: HashMap<String, User>,
find_error: Option<Error>,
save_error: Option<Error>,
}
impl MockRepositoryBuilder {
fn new() -> Self {
Self {
users: HashMap::new(),
find_error: None,
save_error: None,
}
}
fn with_user(mut self, user: User) -> Self {
self.users.insert(user.id.clone(), user);
self
}
fn with_find_error(mut self, error: Error) -> Self {
self.find_error = Some(error);
self
}
fn build(self) -> MockRepository {
MockRepository {
users: self.users,
find_error: self.find_error,
save_error: self.save_error,
}
}
}
#[tokio::test]
async fn test_with_builder() {
let mock = MockRepositoryBuilder::new()
.with_user(test_user())
.with_save_error(Error::Database("Save failed".into()))
.build();
let service = UserService::new(mock);
// Can find user
let user = service.get_user("1").await.unwrap();
// But save fails
let result = service.update_user(user).await;
assert!(result.is_err());
}
}
In-Memory Test Implementations
For integration tests with real logic but no infrastructure:
pub struct InMemoryUserRepository {
users: Arc<Mutex<HashMap<String, User>>>,
}
impl InMemoryUserRepository {
pub fn new() -> Self {
Self {
users: Arc::new(Mutex::new(HashMap::new())),
}
}
}
#[async_trait]
impl UserRepository for InMemoryUserRepository {
async fn find(&self, id: &str) -> Result<User, Error> {
self.users
.lock()
.unwrap()
.get(id)
.cloned()
.ok_or(Error::NotFound)
}
async fn save(&self, user: &User) -> Result<(), Error> {
self.users
.lock()
.unwrap()
.insert(user.id.clone(), user.clone());
Ok(())
}
async fn delete(&self, id: &str) -> Result<(), Error> {
self.users
.lock()
.unwrap()
.remove(id)
.ok_or(Error::NotFound)?;
Ok(())
}
}
Test Fixture Helpers
#[cfg(test)]
mod fixtures {
use super::*;
pub fn test_user() -> User {
User {
id: "test-id".to_string(),
email: "test@example.com".to_string(),
name: "Test User".to_string(),
}
}
pub fn test_user_with_id(id: &str) -> User {
User {
id: id.to_string(),
email: "test@example.com".to_string(),
name: "Test User".to_string(),
}
}
pub fn test_users(count: usize) -> Vec<User> {
(0..count)
.map(|i| test_user_with_id(&format!("user-{}", i)))
.collect()
}
}
Your Approach
When you see code needing tests:
- Identify external dependencies (traits)
- Suggest mock implementation structure
- Show verification patterns
- Provide test fixture helpers
When you see tests without mocks:
- Suggest extracting trait if tightly coupled
- Show how to create mock implementations
- Demonstrate verification patterns
Proactively suggest mocking strategies for testable, maintainable code.