【Flutter】Json形式のフェイクデータを楽々生成しよう

# 初めに
皆さんはデータ変換処理の[Unit　test](https://docs.flutter.dev/cookbook/testing/unit/introduction)書いていますか？(主に`fromJson`,`toJson`)
筆者は、1パターンだけで済ませてしまっていました。
しかし、データの変換処理のテストを充実させておくと、**仕様の見落としに気付けたり**、**共同開発などにおいて仕様のすり合わせができたり**とメリットが大きいことを学びました。
自作のフェイクデータを大量に用意するには手間がかかりますので、今回は以下のパッケージをご紹介します。

https://pub.dev/packages/data_fixture_dart

こちらは以前投稿した「[【Flutter】fakerでフェイクデータを楽に作成してみよう](https://qiita.com/ILTsubugai/items/d7f6dbb67b3fb7358686)」という記事でご紹介した[faker](https://pub.dev/packages/faker)というパッケージをjson形式に対応していただけているものです。

それでは実際に使ってみましょう！
# 実際に使ってみる
## データモデル
今回のデータモデルでは、[freezed](https://pub.dev/packages/freezed)を使用しております。
```dart: lib/model/person.dart
import 'package:flutter/foundation.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'person.freezed.dart';
part 'person.g.dart';

@freezed
class Person with _$Person {
  const factory Person({
    required String name,
    required int age,
    required String job,
  }) = _Person;

  factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json);
}
```

## パッケージの追加
```console
$ flutter pub add data_fixture_dart
```

## データ変換処理用のファイルを作成
以下で順に見ていきます。

```dart: test/model/person_fixture.dart
import 'package:data_fixture_dart/definitions/fixture_definition.dart';
import 'package:data_fixture_dart/definitions/json_fixture_definition.dart';
import 'package:data_fixture_dart/factories/json_fixture_factory.dart';
import 'package:unit_test_sample/api/demo/person.dart';

extension PersonFixture on Person {
  static _PersonFixtureFactory factory() => _PersonFixtureFactory();
}

class _PersonFixtureFactory extends JsonFixtureFactory<Person> {
  @override
  FixtureDefinition<Person> definition() => define(
        (faker) => Person(
          name: faker.person.name(),
          age: faker.randomGenerator.integer(60, min: 22),
          job: faker.job.title(),
        ),
      );

  @override
  JsonFixtureDefinition<Person> jsonDefinition() => defineJson(
        (Person) => {
          "name": Person.name,
          "age": Person.age,
          "job": Person.job,
        },
      );
}
```
### PersonFixture
`extension B on A`で既存クラスであるAをBという名前で拡張することができます。
ここでは、`factory`メソッドで`_PersonFixtureFactory`のインスタンスを作成しています。
```dart
extension PersonFixture on Person {
  static _PersonFixtureFactory factory() => _PersonFixtureFactory();
}
```
```dart: extensionの使用例
void main(List<String> args) {
  final myName = 'Ken';
  print(myName.introduce); // I'm Ken!!
}

extension StrExt on String {
  String get introduce => "I'm $this";
}
```

### _PersonFixtureFactory
実際にフェイクデータを作成するクラスです。
以下の2つのメソッドは`override`必須です。

- **definition** : `define`によって、生成する`Person`のインスタンスをカスタマイズ可能。
- **jsonDefinition** : `defineJson`によって、生成するJson形式のPersonデータをカスタマイズ可能。

`faker`の使い方は以下で説明しておりますのでご参照ください。

https://qiita.com/ILTsubugai/items/d7f6dbb67b3fb7358686

```dart
class _PersonFixtureFactory extends JsonFixtureFactory<Person> {
  @override
  FixtureDefinition<Person> definition() => define(
        (faker) => Person(
          name: faker.person.name(),
          age: faker.randomGenerator.integer(60, min: 22),
          job: faker.job.title(),
        ),
      );

  @override
  JsonFixtureDefinition<Person> jsonDefinition() => defineJson(
        (Person) => {
          "name": Person.name,
          "age": Person.age,
          "job": Person.job,
        },
      );
}
```
## オブジェクト/JSONの生成
`JsonFixtureFactory<T>`には、オブジェクト(今回は`Person`)やJSONデータの生成方法がいくつか用意されています。

- **makeJsonObject()**
    - 1つ分のPersonデータをJson形式で生成。


- **makeJsonArray(int number)**
    - `number`の数だけ、PersonデータをJson形式で生成。


- **makeJsonObjectFromSingle(Person object)**
    - 引数の`Person`から、PersonデータをJson形式で生成。


- **makeJsonArrayFromMany(List<Person> objects)**
    - 引数の`Person`リストから、PersonデータをJson形式で生成。


- **makeSingle()**
    - `Person`のインスタンスを1つ生成。


- **makeMany(int number)**
    - `number`の数だけ、`Person`のインスタンスを生成。

- **makeSingleWithJsonObject()**
    - PersonインスタンスとそのJsonデータを生成。

- **makeManyWithJsonArray(int number)**
    - `number`の数だけ、PersonインスタンスとそのJsonデータを生成。


## テストの作成
```dart: test/model/person_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:unit_test_sample/model/person.dart';

import 'person_fixture.dart';

void main() {
  test(
    'from Json',
    () {
      final personsWithJsonArray =
          PersonFixture.factory().makeManyWithJsonArray(100);

      for (final personWithJson in personsWithJsonArray) {
        final actual = Person.fromJson(personWithJson.json);
        final expected = personWithJson.object;
        expect(actual, expected);
      }
    },
  );

  test(
    'to Json',
    () {
      final personsWithJsonArray =
          PersonFixture.factory().makeManyWithJsonArray(100);

      for (final personWithJson in personsWithJsonArray) {
        final actual = personWithJson.object.toJson();
        final expected = personWithJson.json;
        expect(actual, expected);
      }
    },
  );
}
```

## テストの実施
```console
$ flutter test test/model/person_test.dart
```

# 最後に
今回は、data_fixture_dartを使用して、Json形式のフェイクデータの作成とテストを実施しました。
フェイクデータの重要性には最近気付かされたばかりですが、個人開発やお仕事においても忘れずに精進しようと思います。