Fakerを使って、テスト用のCSVファイルを簡単に生成したい

CSVをアップロードして、データベースのデータをアップデートできる機能を開発することって、よくありますよね？
そんなとき、本当に動作するのかテストがしたいけど、ダミーのデータを自作するのは難しいってことがよくあると思います。

そこで今回は、アップロードしてテストするときに使えるCSVファイルをお手軽に生成することができるFakerの使い方を見ていきたいと思います。

# Fakerとは？
[公式ドキュメントはこちら](https://faker.readthedocs.io/en/master/)です。

Fakerは、テスト用のダミーデータ（例えば、名前、住所、電話番号、メールアドレスなど）を生成するためのライブラリです。

データの生成そのものに特化していて、偽の名前や住所を生成する際に使います。単独で使用でき、簡単に利用可能です。
独自のスクリプトやテストコードで直接使用して、テストデータを手動で生成したり、シンプルにデータを埋め込んだりすることができます。

FakerはPythonがインストールされているPCで使用できます。Djangoプロジェクトを開発している際には、特に使いやすいライブラリだと思います。

# 導入方法
以下のコマンドをターミナルに打ち込むだけで、簡単にインストールできます。
```terminal
pip install faker
```

入っているか確認したいときはこちら
```terminal
pip show faker
```

# CSVファイルを生成する手順
今回はよくありがちな従業員情報をCSVファイルに入れて、それをアップロードしてデータベースに保存する機能のテストに使いたいときを想定して進めます。

## 1. 生成用のスクリプトを作成

以下のように.pyファイルを作成します。
どこに作成してもOKですが、もしDjangoプロジェクトを開発しているようであれば、プロジェクトのルートディレクトリに作成すると使い勝手が良いでしょう。

```Python
from faker import Faker
import csv
import random

fake = Faker('ja_JP')  # 日本語のデータを生成するためにja_JPロケールを使用

# 性別の選択肢
genders = ['男', '女']

# 所属事業所のリスト（地域名＋支店）
offices = [
    '東京支店', '大阪支店', '名古屋支店', '福岡支店', '札幌支店',
    '仙台支店', '広島支店', '京都支店', '横浜支店', '神戸支店'
]

# 所属部署1のリスト（部署名）
departments_1 = ['営業部', '開発部', '総務部', '人事部', '財務部']

# 所属部署2のリスト（課名）
departments_2 = ['営業一課', '営業二課', '開発一課', '開発二課', '総務一課']

# 重複しないメールアドレスを生成するためのセット
email_set = set()

# CSVファイルに書き込むためにファイルを開く。ここで生成されるCSVファイル名が定義できます
with open('test_data.csv', mode='w', newline='') as file:
    writer = csv.writer(file)
    
    # CSVのヘッダー（1行目に入れる列の名称）をここで定義。A列、F~G列を空白にしたい
    writer.writerow([
        '',
        '社員番号', '所属事業所', '所属部署1', '所属部署2', 
        '', '', 
        '苗字', '名前', '苗字の読み仮名', '名前の読み仮名',
        'メールアドレス', '性別', '生年月日', '入社日'
    ])
    
    # 2万件のデータを生成
    for i in range(20000):
        # 名前とカタカナを生成
        last_name = fake.last_name()
        first_name = fake.first_name()
        last_name_kana = fake.last_kana_name()
        first_name_kana = fake.first_kana_name()
        
        # 生年月日と入社日を生成（過去のデータとして）
        birth_date = fake.date_of_birth(minimum_age=18, maximum_age=60)
        hire_date = fake.date_between_dates(date_start=birth_date, date_end=fake.date_this_year())
        
        # 生年月日と入社日を西暦8桁の数値型に変換
        birth_date_str = birth_date.strftime('%Y%m%d')
        hire_date_str = hire_date.strftime('%Y%m%d')
        
        # ランダムな性別を選択
        gender = random.choice(genders)
        
        # 所属事業所、部署1、部署2をランダムに選択
        office = random.choice(offices)
        department_1 = random.choice(departments_1)
        department_2 = random.choice(departments_2)

        # メールアドレスを生成（重複しないようにチェック）
        email = fake.email()
        while email in email_set:
            email = fake.email()
        email_set.add(email)

        # 実際に入れるデータの定義。ヘッダーでA列、F~G列を空白にしたので、ここでも''を使って空白を入れる
        writer.writerow([
            '',                     # A列: 空白
            i + 1,                  # B列: 社員番号
            office,                 # C列: 所属事業所
            department_1,           # D列: 所属部署1
            department_2,           # E列: 所属部署2
            '', '',                 # F~G列: 空白
            last_name,              # H列: 苗字
            first_name,             # I列: 名前
            last_name_kana,         # J列: 苗字の読み仮名
            first_name_kana,        # K列: 名前の読み仮名
            email,                  # L列: メールアドレス
            gender,                 # M列: 性別
            birth_date_str,         # N列: 生年月日
            hire_date_str           # O列: 入社日
        ])

print("テスト用CSVファイルの生成が完了しました。")
```

今回は、テストしたいアプリケーションにすでにテンプレートのCSVがあり、そのテンプレート通りのCSVファイルが欲しい場合、必須事項以外の生成をしたくない時など、なんらかの理由でcsvの途中に空白列を差し込みたい時を想定して、空白を入れる想定でサンプルコードを作っています。

もちろん、空白列がない場合は`writer.writerow`に、`''`を含めないように書けばOKです。

ほかにもバリデーションのチェックのために社員番号がA1234みたいな英数字で作られる場合を想定したもので生成したい場合は以下のように書くこともできます。

```
employee_number = f"EMP{100123 + i}"
```

ほかにも、英語や日本語が混在しているデータを生成したい場合は以下のように書きます。
※以下はご覧の通り`import csv`していないため生成したダミーデータを、ターミナルに出力するだけですが、先ほどのサンプルコードと適宜マージしてご活用ください

```Python
from faker import Faker

# 日本語のデータ生成用インスタンス
fake_jp = Faker('ja_JP')

# 英語のデータ生成用インスタンス
fake_en = Faker('en_US')

# 日本語の名前と住所を生成
jp_first_name = fake_jp.first_name()
jp_last_name = fake_jp.last_name()
jp_address = fake_jp.address()

# 英語の名前と住所を生成
en_first_name = fake_en.first_name()
en_last_name = fake_en.last_name()
en_address = fake_en.address()

print(f"日本語の名前: {jp_last_name} {jp_first_name}")
print(f"日本語の住所: {jp_address}")
print(f"英語の名前: {en_first_name} {en_last_name}")
print(f"英語の住所: {en_address}")
```

ほかにも便利な機能がいろいろありますので、[公式ドキュメントのStandard Providers](https://faker.readthedocs.io/en/stable/providers.html)を参考にしてみてください。


## 生成コマンドを実行
先ほどのテスト生成スクリプトを保存したディレクトリにcdして、pythonコマンドを実行すると、同じディレクトリにcsvが生成されます。

```terminal
python 生成スクリプトのファイル名
```