Rustでテストコードを書くとき、ダミーの名前・住所・メールアドレスなどを手動でハードコードしていませんか。テストケースが増えるたびにコピペが膨らみ、可読性も保守性も下がっていきます。
fakeクレートは、名前・住所・電話番号・UUID・日時といった多種多様なフェイクデータをワンライナーで生成できるRust用ライブラリです。累計ダウンロード数は1,000万回を超え(出典: crates.io)、GitHubスター数は約1,200(出典: GitHub)と、Rustのテスト補助クレートとして広く採用されています。
fakeクレートの基本情報
| 項目 | 内容 |
|---|---|
| 最新バージョン | 4.4.0(2025年8月リリース) |
| 最小Rustバージョン | 1.63 |
| ライセンス | MIT / Apache-2.0 デュアルライセンス |
| リポジトリ | github.com/cksac/fake-rs |
| 対応ロケール数 | 11(JA_JP含む) |
| fakerモジュール数 | 22 |
2016年の初版公開以降、メンテナのcksac氏を中心に継続的にアップデートされています。v4系ではderiveマクロの強化やfeatureフラグの整理が行われ、実用性がさらに向上しました。
セットアップ
Cargo.tomlの[dev-dependencies]にfakeクレートを追加します。deriveフィーチャーを有効にすると#[derive(Dummy)]マクロが使えるようになります。
[dev-dependencies]
fake = { version = "4.4", features = ["derive"] }
UUID・日時・Decimal型のフェイクデータが必要な場合は、対応するフィーチャーフラグを追加します。
[dev-dependencies]
fake = { version = "4.4", features = ["derive", "uuid", "chrono", "rust-decimal"] }
uuid = { version = "1", features = ["v4"] }
chrono = "0.4"
基本的なデータ生成
人名・住所・電話番号
fakerモジュール配下のサブモジュールからジェネレータを取得し、.fake()メソッドで値を生成します。
use fake::faker::name::en::*;
use fake::faker::address::en::*;
use fake::faker::phone_number::en::*;
use fake::Fake;
fn main() {
let full_name: String = Name().fake();
let city: String = CityName().fake();
let phone: String = PhoneNumber().fake();
println!("Name: {full_name}"); // 例: "Telly Gorczany"
println!("City: {city}"); // 例: "North Allentown"
println!("Phone: {phone}"); // 例: "1-234-567-8901"
}
数値・真偽値・Lorem
use fake::faker::number::en::*;
use fake::faker::boolean::en::*;
use fake::faker::lorem::en::*;
use fake::Fake;
fn main() {
let digit: String = Digit().fake();
let flag: bool = Boolean(50).fake(); // 50%の確率でtrue
let sentence: String = Sentence(5..10).fake();
println!("{digit}, {flag}, {sentence}");
}
インターネット関連(メール・URL・ユーザー名)
use fake::faker::internet::en::*;
use fake::Fake;
fn main() {
let email: String = FreeEmail().fake();
let username: String = Username().fake();
let ipv4: String = IPv4().fake();
println!("{email}, {username}, {ipv4}");
}
JA_JPロケールで日本語データを生成する
fakeクレートは11のロケールに対応しており、JA_JPを指定すると日本語の名前や住所を生成できます。
対応ロケール一覧:
| ロケール | 言語・地域 |
|---|---|
| EN | 英語 |
| JA_JP | 日本語 |
| ZH_CN | 中国語(簡体字) |
| ZH_TW | 中国語(繁体字) |
| FR_FR | フランス語 |
| DE_DE | ドイツ語 |
| IT_IT | イタリア語 |
| PT_BR | ポルトガル語(ブラジル) |
| PT_PT | ポルトガル語(ポルトガル) |
| AR_SA | アラビア語 |
| CY_GB | ウェールズ語 |
日本語ロケールの使用例は次の通りです。
use fake::faker::name::raw::*;
use fake::locales::JA_JP;
use fake::Fake;
fn main() {
let name: String = Name(JA_JP).fake();
let first: String = FirstName(JA_JP).fake();
let last: String = LastName(JA_JP).fake();
println!("{name}"); // 例: "山下 湊翔"
println!("{last} {first}");
}
rawモジュール経由でインポートすると、ジェネレータの引数にロケールを渡す形式になります。英語ロケール(enモジュール)と日本語ロケール(raw + JA_JP)を同一テストファイル内で混在させることも可能です。
Dummyトレイトとderive macroの活用
テストで使う構造体全体をフェイクデータで埋めたいケースは多くあります。fakeクレートの#[derive(Dummy)]マクロを使えば、構造体の各フィールドに対して自動的にダミー値を生成できます。
基本的なderive
use fake::{Dummy, Fake, Faker};
#[derive(Debug, Dummy)]
struct User {
#[dummy(faker = "1000..9999")]
id: u64,
#[dummy(faker = "fake::faker::name::en::Name()")]
name: String,
#[dummy(faker = "fake::faker::internet::en::FreeEmail()")]
email: String,
}
#[test]
fn test_user_creation() {
let user: User = Faker.fake();
assert!(user.id >= 1000 && user.id < 9999);
assert!(!user.name.is_empty());
assert!(user.email.contains('@'));
}
#[dummy(faker = "...")]アトリビュートで、フィールドごとにジェネレータを指定できます。Rangeを渡せば数値の範囲指定になり、faker::*のジェネレータ型を渡せば該当カテゴリのフェイクデータが入ります。
enumへの適用
Dummyはenumにも対応しています。各バリアントがランダムに選択されます。
use fake::{Dummy, Fake, Faker};
#[derive(Debug, Dummy)]
enum Status {
Active,
Inactive,
Suspended,
}
#[derive(Debug, Dummy)]
struct Account {
#[dummy(faker = "1..1000")]
id: u32,
status: Status,
}
#[test]
fn test_account_status_variation() {
let accounts: Vec<Account> = (0..100).map(|_| Faker.fake()).collect();
// 100件生成すれば各Statusが少なくとも1件は含まれる可能性が高い
let has_active = accounts.iter().any(|a| matches!(a.status, Status::Active));
let has_inactive = accounts.iter().any(|a| matches!(a.status, Status::Inactive));
assert!(has_active || has_inactive);
}
Dummyトレイトの手動実装
#[derive(Dummy)]で対応できない複雑なロジック(例: フィールド間の制約がある場合)は、Dummyトレイトを手動で実装します。
use fake::{Dummy, Fake, Faker};
use rand::Rng;
struct DateRange {
start: u32,
end: u32,
}
impl Dummy<Faker> for DateRange {
fn dummy_with_rng<R: Rng + ?Sized>(_config: &Faker, rng: &mut R) -> Self {
let start = rng.gen_range(1..100);
let end = rng.gen_range(start..start + 50);
DateRange { start, end }
}
}
dummy_with_rngメソッド内で乱数生成器(rng)を直接操作できるため、フィールド同士の依存関係を表現できます。
全22 fakerモジュール早見表
fakeクレートが提供するfakerモジュールの全体像を整理します。
| モジュール名 | 生成データの例 | 主なジェネレータ型 |
|---|---|---|
| name | 人名(フル・姓・名) | Name, FirstName, LastName |
| address | 住所・都市・郵便番号 | CityName, StreetName, ZipCode |
| phone_number | 電話番号 | PhoneNumber, CellNumber |
| company | 会社名・業種 | CompanyName, Bs, BsAdj |
| internet | メール・URL・IP・UserAgent | FreeEmail, IPv4, Username |
| lorem | ダミーテキスト | Word, Sentence, Paragraph |
| number | 数字文字列 | Digit, NumberWithFormat |
| boolean | 真偽値 | Boolean |
| job | 職業名 | Title, Field, Seniority |
| finance | クレジットカード番号 | Bic, Isin |
| creditcard | カード番号 | CreditCardNumber |
| currency | 通貨コード・名称 | CurrencyCode, CurrencyName |
| color | カラーコード・色名 | HexColor, RgbColor |
| barcode | バーコード | Isbn, Isbn13 |
| filesystem | ファイルパス・拡張子 | FilePath, FileExtension |
| automotive | 車両ナンバー | LicencePlate |
| administrative | 行政区分 | HealthInsuranceCode |
| markdown | Markdown文字列 | 各種Markdown要素 |
| chrono | 日時(chrono型) | DateTime, Date, Time |
| time | 日時(time型) | DateTime, Date, Time |
| http | HTTPステータス・メソッド | RfcStatusCode |
| impls | 内部実装用 | ― |
chrono・time・httpモジュールはそれぞれ同名のフィーチャーフラグを有効にする必要があります。
フィーチャーフラグの選定ガイド
fakeクレートは必要な機能だけをオプトインできるよう、多数のフィーチャーフラグを用意しています。
| フラグ名 | 連携先クレート | 用途 |
|---|---|---|
derive | dummy(proc-macro) | #[derive(Dummy)]マクロ |
chrono | chrono | NaiveDate/DateTime<Utc>等の生成 |
time | time | OffsetDateTime/Date等の生成 |
uuid | uuid | Uuid(v1〜v5)の生成 |
rust-decimal | rust_decimal | Decimal型の生成 |
bigdecimal | bigdecimal | BigDecimal型の生成 |
chrono-tz | chrono-tz | タイムゾーン付き日時 |
geo | geo-types | 緯度経度・ポイント |
glam | glam | ベクトル・行列型 |
http | http | HTTPメソッド・ステータスコード |
bson_oid | bson | MongoDB ObjectId |
ulid | ulid | ULID |
ferroid | ferroid | Ferroid型 |
base64 | base64 | Base64文字列 |
always-true-rng | rand_core | Optional型を常にSomeにする |
プロジェクトで利用している型に合わせてフラグを追加すれば、テストコード内でシームレスにフェイクデータを生成できます。
chronoとの連携例
use fake::faker::chrono::en::*;
use fake::Fake;
use chrono::{NaiveDate, NaiveDateTime};
#[test]
fn test_fake_dates() {
let date: NaiveDate = Date().fake();
let datetime: NaiveDateTime = DateTime().fake();
// chrono型がそのまま返るため、追加のパースが不要
assert!(date.year() > 0);
println!("{date}, {datetime}");
}
uuidとの連携例
use fake::uuid::UUIDv4;
use fake::Fake;
use uuid::Uuid;
#[test]
fn test_fake_uuid() {
let id: Uuid = UUIDv4.fake();
assert_eq!(id.get_version(), Some(uuid::Version::Random));
}
再現可能なテストのためのシード固定
テストの再現性を確保するには、乱数生成器のシードを固定します。fakeはrandクレートのRngトレイトと互換性があるため、StdRng::seed_from_u64を使えば毎回同じフェイクデータを得られます。
use fake::{Fake, Faker};
use rand::SeedableRng;
use rand::rngs::StdRng;
#[test]
fn test_deterministic_fake() {
let mut rng = StdRng::seed_from_u64(42);
let name1: String = Faker.fake_with_rng(&mut rng);
let mut rng2 = StdRng::seed_from_u64(42);
let name2: String = Faker.fake_with_rng(&mut rng2);
assert_eq!(name1, name2); // 同一シードなら同じ値
}
CI環境では「失敗時にシード値をログ出力 → 再現テスト」というワークフローが有効です。
Vecやコレクションの一括生成
テストで複数件のダミーデータが必要な場合、fake!マクロやイテレータを使って一括生成できます。
use fake::{Fake, Faker};
use fake::faker::name::en::Name;
#[test]
fn test_bulk_generation() {
// イテレータで10件生成
let names: Vec<String> = (0..10)
.map(|_| Name().fake())
.collect();
assert_eq!(names.len(), 10);
// Rangeを使った数値の一括生成
let scores: Vec<u32> = (0..5)
.map(|_| (0u32..100).fake())
.collect();
assert!(scores.iter().all(|s| *s < 100));
}
テストデータ生成の代替手法との比較
Rustにはfake以外にもテストデータ生成の手段があります。目的に応じて使い分けるのが効果的です。
| 観点 | fake | proptest | quickcheck |
|---|---|---|---|
| 主な用途 | リアルなダミーデータ生成 | プロパティベーステスト | プロパティベーステスト |
| 生成データの種類 | 名前・住所等のドメインデータ | 型に基づくランダム値 | 型に基づくランダム値 |
| 日本語ロケール | JA_JPサポートあり | なし | なし |
| derive macro | #[derive(Dummy)] | proptest!マクロ | #[derive(Arbitrary)] |
| 失敗時の自動縮小 | なし | あり(shrinking) | あり(shrinking) |
| 外部型との連携 | chrono/uuid等をフィーチャーで対応 | proptest-deriveで拡張 | quickcheckトレイト実装 |
| 累計ダウンロード数 | 約1,025万 | 約9,413万 | 約4,639万 |
fakeが適しているケース:
- テストデータにリアルな外見(人名・住所・メールアドレス等)を求める場合
- 日本語のテストデータが必要な場合
- 既存の構造体にまとめてダミー値を投入したい場合
proptest/quickcheckが適しているケース:
- 関数の不変条件を網羅的に検証したい場合
- 失敗ケースの最小再現(shrinking)が重要な場合
- 境界値・エッジケースの自動探索が必要な場合
実務では「fakeでリアルなテストデータを用意し、proptestで不変条件を検証する」という組み合わせが有効です。両者は競合ではなく補完関係にあります。
実務でのテスト設計パターン
パターン1: リポジトリ層のテストデータ
データベースのCRUDテストでは、Dummyを実装した構造体を使うとテストの見通しが良くなります。
use fake::{Dummy, Fake, Faker};
#[derive(Debug, Clone, Dummy)]
struct CreateUserInput {
#[dummy(faker = "fake::faker::name::en::Name()")]
name: String,
#[dummy(faker = "fake::faker::internet::en::FreeEmail()")]
email: String,
#[dummy(faker = "18..65u32")]
age: u32,
}
#[test]
fn test_create_user() {
let input: CreateUserInput = Faker.fake();
// repositoryにinputを渡してテスト
assert!(!input.name.is_empty());
assert!(input.email.contains('@'));
assert!(input.age >= 18 && input.age < 65);
}
パターン2: APIレスポンスのモック
外部APIのレスポンス型にDummyを実装しておくと、結合テストの前段階で単体テストを素早く回せます。
use fake::{Dummy, Fake, Faker};
#[derive(Debug, Dummy, serde::Serialize)]
struct ApiResponse {
#[dummy(faker = "200..299u16")]
status: u16,
#[dummy(faker = "fake::faker::lorem::en::Sentence(3..8)")]
message: String,
}
#[test]
fn test_api_response_handling() {
let resp: ApiResponse = Faker.fake();
let json = serde_json::to_string(&resp).unwrap();
assert!(json.contains("status"));
}
パターン3: テストヘルパー関数
プロジェクト全体で共通のフェイクデータ生成関数を用意しておくと、テストコードの重複を減らせます。
use fake::{Fake, Faker};
use fake::faker::name::en::Name;
use fake::faker::internet::en::FreeEmail;
/// テスト用のユーザー情報を生成するヘルパー
fn fake_user() -> (String, String) {
let name: String = Name().fake();
let email: String = FreeEmail().fake();
(name, email)
}
#[test]
fn test_with_helper() {
let (name, email) = fake_user();
assert!(!name.is_empty());
assert!(email.contains('@'));
}
トラブルシューティング
コンパイルエラー: the trait Dummy<Faker> is not implemented
#[derive(Dummy)]を使う場合、Cargo.tomlでderiveフィーチャーが有効になっているか確認してください。
fake = { version = "4.4", features = ["derive"] }
chrono::NaiveDateのフェイクデータが生成できない
chronoフィーチャーが無効だとコンパイルエラーになります。
fake = { version = "4.4", features = ["derive", "chrono"] }
ロケール指定時の型エラー
英語ロケール用のenモジュールとマルチロケール用のrawモジュールでは、ジェネレータの型シグネチャが異なります。rawモジュールの場合はロケール型を引数に渡す必要があります。
// OK: enモジュール(ロケール引数なし)
use fake::faker::name::en::Name;
let name: String = Name().fake();
// OK: rawモジュール(ロケール引数あり)
use fake::faker::name::raw::Name;
use fake::locales::JA_JP;
let name: String = Name(JA_JP).fake();
まとめ
fakeクレートは、Rustプロジェクトのテスト品質を高めるための強力なデータ生成ツールです。
- 22種のfakerモジュールで人名・住所・メール・URL・金融データまで幅広く対応
- JA_JPを含む11ロケールで多言語テストデータを生成可能
#[derive(Dummy)]によって構造体・enumへのダミーデータ注入がワンステップ- chrono・uuid・rust_decimalなどの主要クレートとフィーチャーフラグで連携
- シード固定で再現可能なテストを実現
テストの信頼性と保守性を同時に高めたい場合、fakeクレートの導入を検討してみてください。公式ドキュメントはdocs.rs/fake、ソースコードはgithub.com/cksac/fake-rsから参照できます。