話題沸騰ポットに対して Property based testing を試してみる (1)蓋の開け閉め、水を充填させる

#はじめに
[Property based testing を試してみよう](https://qiita.com/freddiefujiwara/items/e345f4a0610bf08deea7)に引き続き
[fast-check](https://github.com/dubzzz/fast-check)を使ってProperty based testingを試しています
fast-checkは状態をランダムウォークさせて失敗するテストケースを見つける方法も[実装されてる](https://github.com/dubzzz/fast-check/tree/master/example/004-stateMachine/musicPlayer)みたいですので後ほど状態に関しても試してみたいと思います

#題材
後ほど状態遷移に関しては挑戦するとして、なにかいい題材はないかなと検索してところ
[テスト設計コンテストU-30クラス](http://aster.or.jp/business/contest/rulebooku30.html)でテストベースに指定されている
[「話題沸騰ポット要求仕様書 (GOMA‐1015型) 第７版](http://www.sessame.jp/workinggroup/WorkingGroup2/POT_Specification.htm)にすることにしました.
理由としては、後ほど試したい状態遷移のProperty based testingができそうなこと、
過去に色々な方がテスト設計を試みられているので、こちら参考にできそうだという理由からです。

#準備
[こちら](https://github.com/freddiefujiwara/goma-1015/blob/feature/fill/__tests__/lib/index.spec.ts)に今回実装したコードを配置してみました。
Nodejsの環境が手元にあれば、試すことができます。

```bash
git clone https://github.com/freddiefujiwara/goma-1015.git
cd goma-1015
npm i
npm test
```
#蓋の開け閉め
##準備
Goma1015にopenとcloseという機能をつけます
いま蓋が開いているか、閉じているかを確認するために
isOpenという機能もついています
##Property based testing
Property based  testingとしてはランダムに開け閉めをして
開いている、閉じているに関わらずopenすると蓋が開いて
closeすると蓋が閉じているかを確認します
fc.boolean()を使ってランダムにtrue/falseを発生させ
trueであれば、蓋を開け、falseであれば蓋を閉じます
実際の実装は下記になります

```JavaScript
import fc from 'fast-check'
import Goma1015 from '../../src/lib/index'

describe('Goma1015', () => {
  it('can create new instance', () => {
    const g = new Goma1015()
    expect(g).not.toBeNull()
    expect(g).toBeInstanceOf(Goma1015)
  })
  it('can open or close', () => {
    const g = new Goma1015()
    expect(g.open).toBeDefined()
    expect(g.close).toBeDefined()
    expect(g.isOpen).toBeDefined()
    expect(g.isOpen()).toBe(false)
    fc.assert(
      fc.property(fc.boolean(), b => {
        if (b) {
          g.open()
          expect(g.isOpen()).toBe(true)
          return
        }
        g.close()
        expect(g.isOpen()).toBe(false)
      }),
    )
  })
})
```
##水を充填させる

次に、ポットに水を充填させましょう
ボットに事前にfillと満タンになったかどうかを確認するfullという機能を追加しておきましょう
[要求仕様書](http://www.sessame.jp/workinggroup/WorkingGroup2/POT_Specification_v7.PDF)には書いてないですが下記とします

- 蓋が開いていないと、水が入れられない (*this is not openの例外が発生)
- マイナスの容量の水は入れられない (*this can't be filled with negative numberの例外が発生)
- 1000ml以上は入れられない (*this is Fullの例外が発生)

これらをProperty based testingで確認していきましょう
fc.nat(1000)を使って1000mlまでの任意の容量の水を発生させ確認していきます

```JavaScript
import fc from 'fast-check'

import Goma1015 from '../../src/lib/index'

describe('Goma1015', () => {
  .
  .
  .
  it('can fill', () => {
    let g = new Goma1015()
    expect(g.fill).toBeDefined()
    expect(() => g.fill(15)).toThrowError(/is not open/)
    g.open()
    expect(() => g.fill(-1)).toThrowError(/can't be filled with negative number/)
    expect(g.full).toBeDefined()
    expect(g.full()).toBe(false)
    g.fill(1000)
    expect(g.full()).toBe(true)
    expect(() => g.fill(1)).toThrowError(/is full/)
    g = new Goma1015()
    g.open()
    let water = 0
    fc.assert(
      fc.property(fc.nat(1000), w => {
        if (water + w > 1000) {
          expect(() => g.fill(w)).toThrowError(/is full/)
          return
        }
        g.fill(w)
        water += w
        expect(g.full()).toBe(1000 == water)
      }),
    )
  })
})
```

#最後に
次は[注いで](https://qiita.com/freddiefujiwara/items/c7158c87b82061bff396)みたいと思います
また、コードにもし間違いありましたら[Pull request](https://github.com/freddiefujiwara/goma-1015)は大歓迎です。
長くなってしまいましたが　最後まで読んでいただきありがとうございました。