【Flutter】fakerでフェイクデータを楽に作成してみよう

### 初めに
皆さんは、フェイクデータをどのようにご用意されていますか？
筆者は、一つのフェイクデータを用意し、複製していました。
そんな味気ないデバッグを改善するために、今回は以下のパッケージをご紹介します。

https://pub.dev/packages/faker

[faker](https://pub.dev/packages/faker)では、住所や位置情報、人物名など多数のフェイクデータが用意されています。


|[address](#address)|[conference](#conference)|[**color**](#color)|
|:----:|:----:|:----:|
|[**company**](#company)|[**currency**](#currency)|[**food**](#food)|
|[**geo**](#geo)|[**guid**](#guid)|[**image**](#image)
|[**internet**](#internet)|[**job**](#job)|[**jwt**](#jwt)|[**lorem**](#lorem)|
|[**person**](#person)|[**phoneNumber**](#phonenumber)|[**sport**](#sport)
|[**vehicle**](#vehicle)|[**dateTime**](#datetime)|[**animal**](#animal)|

### address

- zipCode(郵便番号)
    - `01442-2025`, `22422`, `33225`, `60844-3388`
    - 日本仕様の7桁のものは存在せず、アメリカ仕様の9桁、他国で一般的な5桁が用意されています。

```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  // 郵便番号
  print(faker.address.zipCode()); // 56274-7202
  // 建物番号
  print(faker.address.buildingNumber()); // 526657
  // 街の名前
  print(faker.address.city()); // Concepcionland
  // 街のプレフィックス
  print(faker.address.cityPrefix()); // East Port
  // 街のサフィックス
  print(faker.address.citySuffix()); // mouth
  // 大陸名
  print(faker.address.continent()); // Europe
  // 国名
  print(faker.address.country()); // United Arab Emirates
  // 国コード
  print(faker.address.countryCode()); // NZ
  // 地方の地域の名前？
  print(faker.address.neighborhood()); // Seven Hills Area
  // 州名
  print(faker.address.state()); // Alaska
  // 州の略語
  print(faker.address.stateAbbreviation()); // NJ
  // {state: 州の略語, abbreviation: 州名} <- 逆？
  print(faker.address.stateAsMap()); // {state: MS, abbreviation: Mississippi}
  // 建物番号 人物名 道路のサフィックス
  print(faker.address.streetAddress()); // 254204 Cremin Corner
}
```

### conference

世界的な会議の名称
```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  print(faker.conference.name()); // The 2010 Caribbean New Media Conference Expo.
}
```

### color

- commonColors(一般的な色)
    - `Black`, `Blue`, `Red`, `Gold`
- allColors（マニアックなものを含む全ての色）
    - `Aqua`, `Baby pink`, `Golren yellow`, `Hot pink`

```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  print(faker.color.commonColor()); // Black
  print(faker.color.color()); // Dark cornflower blue
}
```

### company

```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  // 人物名　+ 会社のサフィックス
  print(faker.company.name()); // Quitzon Group
  // (役割のプレフィックス +)　(+ 部門名 +) 身分・立場 
  print(faker.company.position()); // Associate Finance Secretary
  // 会社のサフィックス
  print(faker.company.suffix()); // and Sons
}
```
### currency

```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  // 通貨コード
  print(faker.currency.code()); // JPY
  // 通貨の呼び方
  print(faker.currency.name()); // Yen
}
```

### food

```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  // 郷土料理、伝統料理
  print(faker.food.cuisine()); // Cuban food
  // 一般的な料理
  print(faker.food.dish()); // Corned beef pie
  // レストラン名
  print(faker.food.restaurant()); // Antonio's Pizza
}
```
### geo

```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  // 緯度
  print(faker.geo.latitude()); // 26.16550684148052
  // 経度
  print(faker.geo.longitude()); // -95.90567910639099
}
```
### guid

```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  // グローバル一意識別子
  print(faker.guid.guid()); // 739432ed-ae38-d796-8f53-9ce6702f6b2d
}
```
### image

各プロパティの説明
`int width`: 横幅
`int height`: 縦幅
`List<String> keywords`: `,`区切りで並ぶ
`bool random`: `true`にすると、末尾に、`random = {1~100の数字}`が追加される.
`random = true`にしないと、重複したURLになってしまう。

```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  print(faker.image.image()); // https://source.unsplash.com/640x480
  print(faker.image
      .image(width: 400, height: 600)); // https://source.unsplash.com/400x600
  print(
    faker.image.image(keywords: ['apple', 'banana', 'orange']),
  ); // https://source.unsplash.com/640x480?apple,banana,orange
  print(
    faker.image.image(
        width: 600, height: 800, keywords: ['monkey', 'tiger'], random: false),
  ); // https://source.unsplash.com/600x800?monkey,tiger
  print(
    faker.image.image(
        width: 600, height: 800, keywords: ['monkey', 'tiger'], random: true),
  ); // https://source.unsplash.com/600x800?monkey,tiger&random=85
}
```
### internet

```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  print(faker.internet.email()); // labadie.perry@ferry.com
  print(faker.internet.freeEmail()); // brenda.terry@hotmail.com
  print(faker.internet.safeEmail()); // granville_shields@example.co.uk
  print(faker.internet.disposableEmail()); // elias_satterfield@spamherelots.com
  print(faker.internet.password()); // :!Qg[`-R|]
  print(faker.internet.password(length: 15)); // #[0)e.j&$fu1?+?
  print(faker.internet.httpUrl()); // http://cole.info
  print(faker.internet.httpsUrl()); // https://monahan.co.uk
  print(faker.internet.domainName()); // feil.com
  print(faker.internet.domainWord()); // nader
  print(faker.internet.ipv4Address()); // 177.48.220.52
  print(
    faker.internet.ipv6Address(),
  ); // 1e71:fcd8:b223:33d0:73d7:135c:16e1:6c6d
  print(
    faker.internet.macAddress(),
  ); // 50:01:ba:93:b4:95
  print(faker.internet.uri('ftp')); // ftp://kohler.ca
  print(
    faker.internet.userAgent(),
  ); // MOT-V9mm/00.62 UP.Browser/6.2.3.4.c.1.123 (GUI) MMP/2.0
  print(
    faker.internet.userAgent(osName: 'mac os'),
  ); // iTunes/4.2 (Macintosh; U; PPC Mac OS X 10.2)
}
```
### job

- jobPrefix（職業のプレフィックス）
    - `Lead`, `Senior`, `Direct`, `Corporate`
- jobAdj(職業の形容詞)
    - `Web`, `Data`, `Group`, `Program`
- jobNoun（職業名）
    - `Supervisor`, `Associate`, `Executive`, `Liason`

```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  // jobPrefix + jobAdj + jobNoun
  print(faker.job.title()); // Senior Directives Coordinator
}
```
### jwt
JSON Web Tokenの略
ヘッダ、ペイロード、署名の3つから成る。

```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  print(faker.jwt.valid(expiresIn: DateTime(2023, 1, 1))); // eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2NzA2ODM0NzIsImV4cCI6MTY3MjQ5ODgwMH0.QPkK6Eog5nKJ7QEsJwGYD9bh6q4Dp-bbsd9J61FFaAQ
  print(faker.jwt.expired()); // eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2NzA2ODM0NzIsImV4cCI6MTY3MDY3OTg3Mn0.DveSqKY6vEH6XG6KPa-5wc7QPgYrpT04dbOKY6Is970
  print(
    faker.jwt.custom(
      expiresIn: DateTime(2023, 2, 2),
      payload: {
        'exp': DateTime.now(),
      },
    ),
  ); // eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NzUyNjM2MDAsImlhdCI6MTY3MDY4MzQ3Mn0.21IGFeI5AG69Lh-BB3Ly9zJTQcnwDwY-dQT4CiGjFAY
}
```
### lorem
意味のない文字列
```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  print(faker.lorem.sentence()); // Ultrices dui sapien eget mi proin sed libero.
  print(faker.lorem.word()); // hac
  print(faker.lorem.sentences(2)); // [Diam donec adipiscing tristique risus nec feugiat in fermentum., Ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at.]
  print(faker.lorem.words(4)); // [purus, facilisi, turpis, consequat]
}
```
### person
- prefix(敬称/称号)
    - `Mr.`, `Mrs.`, `Ms.`, `Dr.`
- suffix(サフィックス)
    - `Jr.`, `Sr.`, `I`, `MD`

- firstName(名前)
    - `Adam`, `Jack`, `Yoshiko`, `Zack`
- lastName(名字)
    - `King` `Howe`, `Jast`, `Davis`
- name((prefix +) 名字 + 名前 (+ suffixes))
    - `Halie Glover`, `Mr. Amalia Schoen`
    - `Mr. Amalia Schoen`
    - `Aleen Bode DDS`
    - `Jayne Moore`

```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  print(faker.person.prefix()); // Mr.
  print(faker.person.suffix()); // DDS
  print(faker.person.firstName()); // Lesley
  print(faker.person.lastName()); // Mohr
  print(faker.person.name()); // Destin Dietrich
}
```
### phoneNumber

```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  print(faker.phoneNumber.de()); // (0361) 000530 - 14
  print(faker.phoneNumber.us()); // 3665873276
}
```
### sport

```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  print(faker.sport.name()); // Running
}
```
### vehicle

乗り物

```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  print(faker.vehicle
      .vehicle()); // {Color: Yellow, Make: Lexus, Model: LC, Year: 1968}
  print(faker.vehicle.asVehicle().color); // White
  print(faker.vehicle.asVehicle().make); // Aston Martin
  print(faker.vehicle.asVehicle().model); // Niro
  print(faker.vehicle.make()); // Honda
  print(faker.vehicle.vin()); // L5YE4K0T7EAZPMECW
  print(faker.vehicle.year()); // 2003
  print(faker.vehicle.model()); // NV3500 HD Cargo
  print(faker.vehicle.yearMakeModel()); // 1997 Mitsubishi Mirage G4
  print(faker.vehicle.colorYearMakeModel()); // Mercedes-AMG SL
}
```
### dateTime

```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  print(faker.date.dateTime()); // 3518-10-26 21:40:47.971659
  print(
    faker.date.dateTimeBetween(
      DateTime(1800, 4, 1),
      DateTime(2023, 1, 1),
    ),
  ); // 1851-07-05 09:55:55.572803
  print(faker.date.year()); // 4239 AD
  print(faker.date.month()); // September
  print(faker.date.time()); // 3:42 PM
  print(faker.date.justTime()); // 18:21
}
```
</details>

### animal
```dart
import 'package:faker/faker.dart';

void main() {
  final faker = Faker();
  print(faker.animal.name()); // Buffalo
}
```

### 実際に使ってみた
```dart
import 'package:faker/faker.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Faker Sample',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    final fakeData = FakeData.generateFakeData(fakeDataCount: 40);
    return Scaffold(
      body: ListView.builder(
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(fakeData[index].name),
            subtitle: Text(
              fakeData[index].lastMessage,
              overflow: TextOverflow.ellipsis,
            ),
          );
        },
        itemCount: fakeData.length,
      ),
    );
  }
}

class FakeData {
  FakeData._();
  static List<Friend> generateFakeData({int fakeDataCount = 30}) {
    return List.generate(
      fakeDataCount,
      (index) {
        final fakeName = faker.person.name();
        final fakeLastMessage = faker.lorem.sentence();
        return Friend(
          name: fakeName,
          lastMessage: fakeLastMessage,
        );
      },
    );
  }
}

class Friend {
  const Friend({
    required this.name,
    required this.lastMessage,
  });
  final String name;
  final String lastMessage;
}
```
|全て同じ|`faker`でフェイクデータ作成|
|:---:|:---:|
|<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2552610/898f7d6d-e471-6559-c25c-5afc27cbc855.png' width='400'>|<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2552610/44b43f0b-00dd-7321-46de-95f207d8f17a.png' width='400'>

名前と、最終メッセージだけを表示する簡単なUIです。
`faker`でフェイクデータを作成した方は、短いメッセージや長いメッセージがランダムに生成させるので、実際のUIに近づけることができます。
文字数が長いフェイクデータを用意することは大変なのでとても便利ですね！

### 終わりに
今回は、フェイクデータを簡単に生成することができるパッケージをご紹介いたしました。
本番環境に近い状態での開発の方がモチベーションも上がりますよね！
筆者は、今後の開発に取り入れていこうと考えています！

最後までお読みいただきありがとうございます。




## 参考

https://www.busoken.com/blog/%E6%B5%B7%E5%A4%96%E3%81%AE%E9%83%B5%E4%BE%BF%E7%95%AA%E5%8F%B7%E4%BA%8B%E6%83%85-expb

https://qiita.com/knaot0/items/8427918564400968bd2b

https://www.lipsum.com/