なに？テスト駆動開発やったことないのかい？まったくキミってやつは！

## ある日のパイセン「テスト書いておいてくれよ！」


そう言われたのだけど…
ボクはテストを書いたことのなかったのさ！

どうなったかって？

Oh...ジーザス

レビューで突き返されちまったよ！
そのうえリファクタリングまでされて。

最終的にパイセンのコードを見よう見まねで
テストを追加していって、マージはされたんだ

そこで、ボクは思ったよ

**テスト書けるかどうか、ボクがテストされるべきだったんだなってね！**


## TDD本というバイブルがあるじゃないか！

テスト駆動開発をはじめよう、という人には
TDD本と呼ばれる[『テスト駆動開発』](https://www.amazon.co.jp/dp/4274217884)というものがあるんだ！

どんな本買って？
あれはまさにバイブルさ。
（ゴシップ好きのトニーの話じゃ、今や机の引き出しに入れてるホテルもあるらしい！）

さっそくボクもTDD本を読んだから、テスト駆動開発というのを、キミに教えてあげようじゃないか！


環境は、vueCLIで、全部入れることができるものさ。
> Vue.js
> TypeScript
> テストライブラリ：[Vue Test Utils](https://vue-test-utils.vuejs.org/ja/)
> テスティングフレームワーク：[Jest](https://jestjs.io/ja/)


今回は、propsにデータを渡したら、
テーブルを表示してくれるcomponentのテストでも書いてみよう

ファイル構成はこんな感じだ

```
src
┣ components
┃ ┗ organisms
┃   ┗ SummaryTable.vue
┗ views
  ┗ Home.vue
tests
 ┗ unit
   ┣ Home.spec.ts
   ┗ SummaryTable.spec.ts
```


## ようこそ、テスト駆動開発の世界へ。いいかい、ルールを守らないと罰則だよ！


環境は整った！さあ、次はなにをする？

まず手始めに、ページのタイトルが表示されるという、テストでも書いてみるかい？

```Home.vue
<template>
    <div>
        <h1>データ一覧</h1>
    </div>
</template>
```

```Home.spec.ts
import { shallowMount } from '@vue/test-utils'
import Component from '@/views/Home.vue'

describe('Testing Home Component', () => {
    it('renders page title', () => {
        const wrapper = shallowMount(Component)
        expect(wrapper.html()).toContain('<h1>データ一覧</h1>')
    })
})
```

このテストがどうなるかって？

もちろん通るに決まってる！楽勝さ！


## おいおい、いきなりテスト書いちゃって。まだまだ子どもだね！


テストは通るさ！
でも、その前にやることがあるだろう？

忘れちゃだめさ。

**テストパターンを書き出さないとな！**
**TODOリストみたいに書き出していって、テストが終わったものから消していくんだ！**

いきなりテストを書くなんて、デートでいきなりホテルに行きたがるようなものさ
（ホテルにはTDD本があるだろうな！）
ガールフレンドに見放されちまうぜ？

もちろんボクたちは全知全能の神じゃない
最初から全部挙げるなんて無理さ！

**テストを書いているときに、新しいテストパターンを思いついたら、追加で書き出せばいいんだよ！**

> テストパターン
> [x] タイトルを表示する
> [ ] テーブルデータが表示される


次は、テーブルデータが表示される、だな！
ユーキャンメイキット！（You can make it !）

```SummaryTable.vue
<template>
    <div>
        <div v-for="item in items" :key="item.id">
            <div v-for="key in Object.keys(item)" :key="key.id">{{ item[key] }}</div>
        </div>
    </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
    name: 'SummaryTable',
    props: {
        items: {
            type: Array,
            require: true
        }
    }
})
</script>
```


## テストが通るまでは別のコードを書くんじゃないよ！トーストを焦がされたいのかい？


それっぽいコードが書けたな！やるじゃないか！

ただねキミ
今やっているのがテスト駆動開発だ、ということを忘れちゃいないかい？

> [ ] テーブルデータが表示される

をテストするのに、親componentから渡ってきた値を、SummaryTableで表示する必要があるのかい？

`親componentから渡ってきた値が、SummaryTableで表示される`
これは別のコードなんだから、別のテストであるべきだ
> テストパターン
> [x] タイトルを表示する
> [ ] テーブルデータが表示される
> [ ] 親componentから渡ってきた値が、SummaryTableで表示される

だから今回は、これだけで十分なのさ

```SummaryTable.vue
<template>
    <div>
	<div>
	    <div>id</div>
	    <div>name</div>
	    <div>email</div>
	</div>
        <div>
            <div>1</div>
            <div>Bob</div>
            <div>bob@email.com</div>
        </div>
        <div>
            <div>2</div>
            <div>Tom</div>
            <div>tom@email.com</div>
        </div>
        <div>
            <div>3</div>
            <div>Sam</div>
            <div>sam@email.com</div>
        </div>
    </div>
</template>
```

むむ、テーブルのヘッダー部分のテストパターンもあったほうがよさそうじゃないか？
忘れないうちに加えておこう

> テストパターン
> [x] タイトルを表示する
> [ ] テーブルヘッダーが表示される
> [ ] テーブルデータが表示される
> [ ] 親componentから渡ってきた値が、SummaryTableで表示される


テーブルヘッダー、テーブルデータのテストは
`Home.spec.ts`と要領は同じだ

```SummaryTable.spec.ts
import { shallowMount } from '@vue/test-utils'
import Component from '@/components/organisms/SummaryTable.vue'

describe('Testing Render Summary Table', () => {

    it('render table heads', () => {
        const wrapper = shallowMount(Component)

        expect(wrapper.html()).toContain('id')
        expect(wrapper.html()).toContain('name')
        expect(wrapper.html()).toContain('email')
    })

    it('render table items', () => {
        const wrapper = shallowMount(Component)
	
        expect(wrapper.html()).toContain(1)
        expect(wrapper.html()).toContain('Bob')
        expect(wrapper.html()).toContain('bob@email.com')
	// TomとSamも同じようにね！
    })
})
```

これで問題なく通るだろう！
イッツアピースオブケーク！（It's a piece of cake !）



## 次のテストを書く前に、コーヒーブレイクでもどうだい？リファクタリングという名のね！

> テストパターン
> [x] タイトルを表示する
> [x] テーブルヘッダーが表示される
> [x] テーブルデータが表示される
> [ ] 親componentから渡ってきた値が、SummaryTableで表示される

さあ、残り1パターンだ！
（実際はもっとあるだろうが、そこは目を瞑ってくれると信じてるぜ、ブラザー）


しかし次のテストを書く前に、リファクタリングをしなきゃいけないのさ！

え、あとでもいいんじゃないかって？

後回しにしてもいいのは、夏休みの宿題だけだぜ！

実際、TDDの進め方に、リファクタリングが入っているんだ！

**テスト駆動開発の進め方**
1. まずはテストを1つ書く
2. すべてのテストを走らせ、新しいテストの失敗を確認する
3. 小さな変更を行う
4. すべてのテストを走らせ、すべて成功することを確認する
5. リファクタリングを行って重複を除去する

-> すべてのテストが通ったら、その機能の実装をする


さあ、やってみよう
こんな感じかい？

```SummaryTable.spec.ts
describe('Testing Render Summary Table', () => {
    const items = [
        { id: 1, name: 'Bob', email: 'bob@email.com' },
        { id: 2, name: 'Tom', email: 'tom@email.com' },
        { id: 3, name: 'Sam', email: 'sam@email.com' }
    ]

    it('render table heads', () => {
        const wrapper = shallowMount(Component)

        Object.keys(items[0]).forEach((key) => {
            expect(wrapper.html()).toContain(key)
        })
    })

    it('render table items', () => {
        const wrapper = shallowMount(Component)

        items.forEach((item) => {
            Object.keys(item).forEach((key) => {
                expect(wrapper.html()).toContain(item[key])
            })
        })
    })
})
```

どうやら、テストは通ってるみたいだな！
![Screen Shot 0003-10-03 at 12.54.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560551/67ff7c46-a5ec-9e01-cc04-3fbb0bbe8e6f.png)



いよいよ最後のテストパターンか！
> テストパターン
> [x] タイトルを表示する
> [x] テーブルヘッダーが表示される
> [x] テーブルデータが表示される
> [ ] 親componentから渡ってきた値が、SummaryTableで表示される


## テスト駆動開発は、2度コードを書く。そんなふうに思ったらキミのテストが間違ってる！


最後のテストパターンはこうだ
> [ ] 親componentから渡ってきた値が、SummaryTableで表示される


テストを書く前に、これまでのテストコードを見返してみてくれ
驚くべきことに気づくはずだ
（きっとキミがアニメの主人公なら、目が飛び出してしまうよ！）

```SummaryTable.spec.ts
describe('Testing Render Summary Table', () => {
    const items = [
        { id: 1, name: 'Bob', email: 'bob@email.com' },
        { id: 2, name: 'Tom', email: 'tom@email.com' },
        { id: 3, name: 'Sam', email: 'sam@email.com' }
    ]
    // これはもうpropsに渡せる状態だ！

    it('render table heads', () => {
        const wrapper = shallowMount(Component)

        Object.keys(items[0]).forEach((key) => {
            expect(wrapper.html()).toContain(key)
        })
	// これをtemplateに組み込めば、itemのkeyが変わっても大丈夫そうだ！
    })

    it('render table items', () => {
        const wrapper = shallowMount(Component)

        items.forEach((item) => {
            Object.keys(item).forEach((key) => {
                expect(wrapper.html()).toContain(item[key])
            })
        })
	// これをtemplateに組み込めば、itemのkeyが変わっても大丈夫そうだ！
    })
})
```


そう、**もうキミはここまでで、次のテストに使えるコードを書いてきているんだ！**
もはや、テストコードは、componentのpropsにitemsをを渡してあげるだけでいい！


```SummaryTable.spec.ts
const wrapper = shallowMount(Component, { propsData: { items } })
```


```SummaryTable.vue
<template>
    <div>
        <div>
            <div v-for="key in Object.keys(getItems[0])" :key="key.id">{{ key }}</div>
        </div>
        <div v-for="item in getItems" :key="item.id">
            <div v-for="key in Object.keys(item)" :key="key.id">{{ item[key] }}</div>
        </div>
    </div>
</template>

<script lang="ts">
import { defineComponent, PropType } from 'vue'
interface Item {
    id: number
    name: string
    email: string
}
// 略
    props: {
        items: {
            type: Object as PropType<Item[]>,
            require: true
        }
    },
    computed: {
        getItems(): Item[] {
            return this.items
        }
    }
// 略
```

なんて素晴らしいんだ！
ちゃんとリファクタリングをしてきたから、
ロジックを新しく考える必要などなく、最後のテストパターンも通すことができた！

> テストパターン
> [x] タイトルを表示する
> [x] テーブルヘッダーが表示される
> [x] テーブルデータが表示される
> [x] 親componentから渡ってきた値が、SummaryTableで表示される




## テスト駆動開発、翼をさずける！

ここまで読んでくれたキミ、ありがとう！

ボクはテスト駆動開発と出会って、翼をさずかった気分だよ。

きっと飛び方をマスターすれば、
どこへでも、何にもぶつからずに、行くことができるさ！

もちろんまずは、
飛んで行っていいかどうか、
テストを通してからにしてくれよ？

**Follow ME !!!**
**I'm sure to follow you back!**
twitter: [@marty_ojiya](https://twitter.com/marty_ojiya)