zenet_logo

-株式会社ゼネット技術ブログ-

テストデータ作成ツールSnowFakeryの使い方まとめ

f:id:zenet-tech:20210316165551j:plain


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#