SnowFakeryとは?
SnowFakeryとは、テストデータ、ダミーデータを作ってくれるツールです。
テストではテストデータが付きものです。リリースする前に本番に近いデータを使い、ソフトが動作をするかをテストします。
FactoryBotのようにダミーデータを作り、単体テストや結合テストをしやすくするツールです。
SnowFakeryの利点
SnowFakeryの利点は、吐き出すデータの型が豊富なことです。json, text, csv, sqlと言ったメジャーなデータ型が存在しています。
データの型が多いとそれだけ対応できるソフトが増えます。通常のソフトは予め使うデータの型が決まっています。例えば、excelならば.xlsxでwordなら.docsと決まっています。そして、これだけ揃っているといろいろなテストツールで使うことができます。
SQLで使えるのは大きな利点であると感じています。なぜなら、多くのソフトでSQLが使われていてテストをするときにテストデータの調達が非常に楽になります。
テストデータ作成ツールは他にもありますが、言語に依存しているケースが多くあります。例えばRubyonRailsの開発でよく使われるFactoryBotではrubyの記法でRails用のテストデータが作られます。その点SnowFakeryでしたら様々な形式でデータが吐き出されるため、基本的にはどの言語でも使えます。そのため、システムのメイン言語を移行する場合でも同様のテストデータを作成し検証することが可能となります。
この柔軟性が一番の売りです。デメリットを上げるとすると、ドキュメントが英語の部分が大半であることかもしれません。
SnowFakeryの基本的な使い方
- var: snowfakery_locale value: ja_JP - object: Contact count: 5 fields: LastName: fake: last_name FirstName: fake: first_name Address__c: fake: address Age__c: random_number: min: 20 max: 65 step: 5
test.yml
snowfakery test.yml --output-format=json -o test.json
コマンドライン
こちらはテスト用のyamlファイルとコマンドです。上のyamlは下のQiitaの記事から引用しました。
yamlは、テストデータの構造を示しています。テストデータは作るソフトのデータ構造に合わせて作ります。このyamlファイルでは、名字、名前、住所、年齢のデータを5つ作ろうとしています。
そして、コマンドでは先程のtest.yml
を読み込んでjson型でtest.json
を出力しようとしています。
基本的にはyamlファイルでほしいデータの構造を書いてsnowfakeryでjsonやcsv、SQLに吐き出す形になります。
snowfakeryの基本的な記述方法
randomに関する記法
random_choiceの書き方
- var: snowfakery_locale value: ja_JP - object: Contact count: 5 fields: LastName: fake: last_name FirstName: fake: first_name size: random_choice: - 大盛 - 中盛 - 少なめ
random_choice.yml
random_choiceとは、リストの中からランダムに選んだ文字列、数字を選んでくれる機能です。
使い道として、決まった選択肢をランダムに選択させたい場合です。
例えば、牛丼の「大盛り、中盛、少なめ」をランダムに選ばせたい場合、上のコードのような書き方ができます。
- var: snowfakery_locale value: ja_JP - object: Contact count: 5 fields: LastName: fake: last_name FirstName: fake: first_name size: random_choice: 大盛り: 50% 中盛: 30% 少なめ: 20%
random_choice_percent.yml
そして、これの発展バージョンは「大盛り、中盛、少なめ」を50%、30%、20%の割合で選ばせたい場合は上のコードの書き方ができます。
- var: snowfakery_locale value: ja_JP - object: Contact count: 5 fields: person_doing_the_task: random_choice: - object: yoshinoya fields: food_name: 牛丼 size: 大盛り LastName: fake: last_name FirstName: fake: first_name - object: katuya fields: food_name: カツ丼 size: 中盛 LastName: fake: last_name FirstName: fake: first_name
katuya_yoshinoya.yml
さらに、かつやと吉野家をランダムに選ばせたい場合は、以下のコードのようになります。ランダムにかつやと吉野家を選んでくれます。
本番機のデータが使えなくても、比率と選択肢がわかっていれば本番機に近いデータを作ることができます。
fakeに関する記法
fakeはダミーデータの要素を作ってくれます。
本番環境はなるべく使わないほうがいいです。本番環境で得たデータなら、ダミーデータを作るよりも、開発環境へ入れるのも簡単です。ですが、その場合開発チームの人数分に本番機のデータを渡すことになります。
そのようなことをすれば、データの流出する確率も高くなります。また、開発が進むにつれて取った本番機のデータも古くなります。そうなると、テストコードが常に正しく動かなくなります。
ダミーデータの値を設定すれば、データ流出をせず、データも古くなっても修復することができます。開発が進んでデータ構造が変化したとしても、設置値を変更すれば対応することができます。
ダミーデータの構築は多少手間ではありますが、初期に対応すれば問題は後半の導入に比べてコストは低くなります。
fakeの書き方
fakeで使われているダミーデータの生成はfakerというライブラリを使っています。fakerのAPIをまとめにある関数を使います。
注意してほしいのは、リンク先に並べられたAPIのような表記はAPIではなく、Fakerの分類です。
例えば、faker.providers.address
があるのですが、これはaddress(住所)に関わる関数がある集まりを指しています。
faker.providers.address
のリンクを開くとaddress()
とかbuilding_number()
が書かれています。試しにbuilding_number()
を使ってみましょう
- var: snowfakery_locale value: ja_JP - object: Contact count: 5 fields: LastName: fake: last_name FirstName: fake: first_name Address_building_number: fake: building_number
building_number.yml (test.ymlの続きです。)
すると、building_number(マンションの〜号室)が入った羅列が出力されます。fake
のあとに関数名を入れると自動的にfakerを使ってテストデータを生成してくれます。
- var: snowfakery_locale value: ja_JP - object: Contact count: 5 fields: LastName: ${{fake.last_name()}} FirstName: ${{fake.first_name()}} Address_building_number: ${{fake.building_number()}}
building_number_code_version.yml
また、fakeを関数みたいに扱うこともできます。こうする関数の引数を扱うことができ、細かく設定をすることができます。
if文の書き方
snowfakeryのyamlファイルではif文を扱うことができます。
たとえば、性別が女性なら女性の名前、と言ったケースで使うことができます。
- var: snowfakery_locale value: ja_JP - object: Contact count: 5 fields: gender: random_choice: - choice: probability: 40% pick: Male - choice: probability: 40% pick: Female - choice: probability: 20% pick: Other LastName: if: - choice: when: ${{gender=='Male'}} pick: fake: last_name_male - choice: when: ${{gender=='Female'}} pick: fake: last_name_female - choice: pick: fake: last_name FirstName: if: - choice: when: ${{gender=='Male'}} pick: fake: first_name_male - choice: when: ${{gender=='Female'}} pick: fake: first_name_female - choice: pick: fake: first_name Address_building_number: ${{fake.building_number()}}
gender_add_name.yaml
上のコードは性別に合わせて名字、名前を変えるようにデータを変更しました。すると、女性なら女性の名前、男性なら男性の名前、ジェンダーレスなら普通の名前、と合わせて変更することができます。
これの方法は、男女の名前、猫の品種による毛の長さ、作品名に紐づくロボットの名前などの生成に使えます。
macroの書き方
macroは、objectとは別に要素を書いて読み込むことができる機能です。
例えば、従業員のデータを生成するときに必ず「部署」、「課」に所属しています。そして、〜課に属している人にデータをくっつけておいてデータを作りたいときに便利です。
- var: snowfakery_locale value: ja_JP - macro: belongs_group fields: department: 生活安全部 division: 生活安全課 - object: Contact include: belongs_group count: 5 fields: gender: random_choice: - choice: probability: 40% pick: Male - choice: probability: 40% pick: Female - choice: probability: 20% pick: Other LastName: if: - choice: when: ${{gender=='Male'}} pick: fake: last_name_male - choice: when: ${{gender=='Female'}} pick: fake: last_name_female - choice: pick: fake: last_name FirstName: if: - choice: when: ${{gender=='Male'}} pick: fake: first_name_male - choice: when: ${{gender=='Female'}} pick: fake: first_name_female - choice: pick: fake: first_name Address_building_number: ${{fake.building_number()}}
belongs_group.yml
上のコードは所属している部署、課を追加したテストデータのコードです。今回は警察の「生活安全」に関わる人のデータを生成しています。
object
内のinclude
はmacroを読み込んでテストデータに組み込んでいます。macroでは「生活安全部生活安全課」の部署のデータ構造を書いています。macroを読み込むことですべてのデータに部署と課が付属したデータが作られます。
varの書き方
varは値を指定することができます。例えば、固定電話、部屋に備え付けの家具、共用で使うコーヒーメーカーなどのデータを各データに共有で持たせたいときに使います。
- var: snowfakery_locale value: ja_JP - macro: belongs_group fields: department: 生活安全部 division: 生活安全課 - var: phone_number_var value: fake: phone_number - object: Contact include: belongs_group count: 5 fields: phone_number: ${{phone_number_var}} gender: random_choice: - choice: probability: 40% pick: Male - choice: probability: 40% pick: Female - choice: probability: 20% pick: Other LastName: if: - choice: when: ${{gender=='Male'}} pick: fake: last_name_male - choice: when: ${{gender=='Female'}} pick: fake: last_name_female - choice: pick: fake: last_name FirstName: if: - choice: when: ${{gender=='Male'}} pick: fake: first_name_male - choice: when: ${{gender=='Female'}} pick: fake: first_name_female - choice: pick: fake: first_name Address_building_number: ${{fake.building_number()}}
use_var.yaml
上のコードは、すべてのデータに同じ固定電話の番号を付けています。
すると、すべての従業員データに固定電話の番号が振り分けられます。
include_fileの記法
include_fileは、別のyamlファイルを読み込むことができます。
include_fileをすることで、ファイルを分割することができて、一つ一つのyamlファイルを小さくすることができます。
- macro: belongs_group fields: department: 生活安全部 division: 生活安全課
child.yml
- var: snowfakery_locale value: ja_JP - include_file: child.yml - var: phone_number_var value: fake: phone_number - object: Contact include: belongs_group count: 5 fields: phone_number: ${{phone_number_var}} gender: random_choice: - choice: probability: 40% pick: Male - choice: probability: 40% pick: Female - choice: probability: 20% pick: Other LastName: if: - choice: when: ${{gender=='Male'}} pick: fake: last_name_male - choice: when: ${{gender=='Female'}} pick: fake: last_name_female - choice: pick: fake: last_name FirstName: if: - choice: when: ${{gender=='Male'}} pick: fake: first_name_male - choice: when: ${{gender=='Female'}} pick: fake: first_name_female - choice: pick: fake: first_name Address_building_number: ${{fake.building_number()}}
include_file.yml
上のコードはinclude_file.ymlがchild.ymlを読み込んでいます。childではbelongs_group
マクロが書かれています。
すると、前のvarの書き方
と同じような動きをします。
参考資料
SnowFakeryドキュメントサイト(英語): https://snowfakery.readthedocs.io/en/stable/
Snowfakery を使用した Salesforce のテストデータ作成: https://qiita.com/shunkosa/items/71e6549a539e2703d2c8
fakerのドキュメントサイト(英語): https://faker.readthedocs.io/en/master/fakerclass.html#