テストデータを簡単に作成することができるrosieの使い方【JavaScript】

今日はクリスマスイブ🎄🎄

~~寂しさを紛らわすために~~時間もあったので記事を書きました。


内容としては、タイトルにもありますがフロントのテストデータを簡単に作成することができる[rosie](https://github.com/rosiejs/rosie)の基本的な使い方についてです。


https://github.com/rosiejs/rosie



## 環境構築

```
mkdir rosie_demo
```

```
yarn add rosie
```

これだけです。

## 使い方

使い方はとてもシンプルです。

1. Factoryを定義する
2. オブジェクをビルドする

### Factoryを定義する

公式のコードを例に説明します。


```javascript
const Factory = require('rosie').Factory;

Factory.define('game')
  .sequence('id')
  .attr('is_over', false)
  .attr('created_at', function() { return new Date(); })
  .attr('random_seed', function() { return Math.random(); })
  .attr('players', ['players'], function(players) {
    if (!players) { players = [{}, {}]; }
    return players.map(function(data) {
      return Factory.attributes('player', data);
    });
  });

Factory.define('player')
  .sequence('id')
  .sequence('name', function(i) { return 'player' + i; })
  .attr('position', ['id'], function(id) {
    const positions = ['pitcher', '1st base', '2nd base', '3rd base'];
    return positions[id % positions.length];
  });
```
まずは以下の部分です。

```javascript
Factory.define('game')
```

#### `Factory.define(factory_name)`

**Factory.define**は後に定義する**attr**や**sequence**ファクトリーのインスタンスを返します。**factory_name**の部分は文字列になります。

```javascript
.sequence('id')
```
**sequenceh**はオートインクリメントしたいものを定義します。

次に以下のコードです。

```javascript
.attr('is_over', false)
```

**attr**は最大3つ引数を受け取ります。

#### `instance.attr(attribute_name, default_value)`

**attribute_name**にはプロパティの名前が入ります。**default_value**にはそのままですがデフォルト値が入ります。

#### `instance.attr(attribute_name, generator_function)`

**generator_function**には以下のようにプロパティの値を生成するための**関数**が入ります。

```javascript
.attr('created_at', function() { return new Date(); })
```

#### `instance.attr(attribute_name, dependencies, generator_function)`

3つの場合、**dependencies**が第二引数になります。
dependenciesはstring型の配列になり、**generator_function**の中で値を生成するためのパラメーターとして使用されます。

```javascript
.attr('players', ['players'], function(players) {
  if (!players) { players = [{}, {}]; }
  return players.map(function(data) {
   return Factory.attributes('player', data);
  });
});
```

### オブジェクをビルドする

以下のように**build**メソッドを使用してオブジェクトを作成します。

```javascript
const game = Factory.build('game', { is_over: true , players: [{ name: "fuga" }, { name:"hoge" }]});
console.log(game)
/*
{ is_over: true,
  players:
   [ { name: 'fuga', id: 1, position: '1st base' },
     { name: 'huga', id: 2, position: '2nd base' } ],
  id: 1,
  created_at: 2018-12-23T08:56:26.520Z,
  random_seed: 0.2721230900040248 }
 */
```

ビルドする際に値を変更してあげることでさまざまなテストケースに対応することができます。

#### `Factory.build(factory_name, attributes, options)`

**factory_name**にはfactoryの名前、attributesにはオブジェクトが入ります。オブジェクトの中で上書きしたいキー、バリューを指定します。上記の例では**is_over**と**plyaers**になります。

また初期データを複数作成したい場合は、下記のように**buildList**を使います。

#### `Factory.buildList(factory_name, size, attributes, options)`

以下のようにsizeを指定してあげるとその数分のテストデータが作成されます。

```javascript
Factory.define("todo")
  .sequence("id")
  .attr("text", ["id"],(id)=> {
    return id % 2 ? "ラーメン食べる": "髪を切る"
  })
  .attr("completed", ["text"], (text) => {
    return text === "ラーメン食べる" ? true : false
  });

const todos = Factory.buildList("todo", 5);
console.log(todos);
/*
[ { id: 1, text: 'ラーメン食べる', completed: true },
  { id: 2, text: '髪を切る', completed: false },
  { id: 3, text: 'ラーメン食べる', completed: true },
  { id: 4, text: '髪を切る', completed: false },
  { id: 5, text: 'ラーメン食べる', completed: true } ]
*/
```
他にも便利なものを紹介しておきます。

### 属性をまとめて定義したい時

以下のように**.attrs**の中に属性を書きます。

```javascript
Factory.define('game')
  .sequence('id')
  .attrs({
    is_over: false,
    created_at: () => new Date(),
    random_seed: () => Math.random()
  });
const game = Factory.build('game');
console.log(game);
/*
{ id: 1,
  is_over: false,
  created_at: 2018-12-23T09:25:43.223Z,
  random_seed: 0.26435655180714024
}
*/
```

### オブジェクトを生成した後に何か処理をしたい時

以下のように**after**を使用してコールバックを定義します。

```javascript
Factory.define('coach')
  .option('buildPlayer', false)
  .sequence('id')
  .attr('players', ['id', 'buildPlayer'], (id, buildPlayer) => {
    if (buildPlayer) {
      return [Factory.build('player', { coach_id: id })];
    }
  })
  .after((coach, options) => {
    if (options.buildPlayer) {
      console.log('built player:', coach.players[0]);
    }
  });

Factory.build('coach', {}, { buildPlayer: true });
```

コールバックが何も返さない場合は、ビルドオブジェクトを最終的な結果として返します。
逆にコールバックが値を返す場合は、その値を返します。


## まとめ

以上でrosieの基本的な使い方を紹介しました。
今度はreduxのactionやselectorのテストなどより実践的な使い方を紹介したいと思います。