<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
	>

<channel>
	<title>TDD | みんたく</title>
	<atom:link href="https://mintaku-blog.net/category/develop/tdd/feed/" rel="self" type="application/rss+xml" />
	<link>https://mintaku-blog.net</link>
	<description>みんたくの技術ブログ</description>
	<lastBuildDate>Wed, 03 Jan 2024 03:13:53 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.0.11</generator>

<image>
	<url>https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2018/06/cropped-ipad-820272_640.jpg?fit=32%2C32&#038;ssl=1</url>
	<title>TDD | みんたく</title>
	<link>https://mintaku-blog.net</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">144480658</site>	<item>
		<title>ドメインのstaticメソッドをmockする</title>
		<link>https://mintaku-blog.net/mock-static/</link>
					<comments>https://mintaku-blog.net/mock-static/#respond</comments>
		
		<dc:creator><![CDATA[みんたく]]></dc:creator>
		<pubDate>Wed, 03 Jan 2024 03:13:37 +0000</pubDate>
				<category><![CDATA[TDD]]></category>
		<category><![CDATA[TypeScript]]></category>
		<guid isPermaLink="false">https://mintaku-blog.net/?p=2442</guid>

					<description><![CDATA[<p>ドメインのファクトリメソッドを呼び出しているメソッドのテストをするときに、いい感じにmockする方法を学んだのでメモしておきます。 ドメインのstaticメ …</p>
The post <a href="https://mintaku-blog.net/mock-static/">ドメインのstaticメソッドをmockする</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></description>
										<content:encoded><![CDATA[<p>ドメインのファクトリメソッドを呼び出しているメソッドのテストをするときに、いい感じにmockする方法を学んだのでメモしておきます。</p>
<h2>ドメインのstaticメソッドをmockする方法</h2>
<p>Interface &amp; Adapter層のGatewayでエンティティをドメインに変換する際に、ドメインの</p>
<p>Driverからデータを取得して、ドメインに変換するメソッドをテストする場合はこんな感じになります。</p>
<p>・NewsGateway.ts</p><pre class="crayon-plain-tag">async getNews(): Promise&lt;News&gt; {
  const newsEntity = await this.newsDriver.getNews();
  return this.convertNews(newsEntity)
}</pre><p>・NewsGateway.test.ts</p><pre class="crayon-plain-tag"> ...

describe('getNews', () =&gt; {
  it('ニュース一覧を取得することができる', async () =&gt; {
    const newsEntity = mock&lt;NewsEntity[]&gt;()
    const news = mock&lt;News&gt;()
      
    const getNewsMock = jest.fn()
    when(getNewsMock).calledWith().defaultReturnValue(newsEntity)
    newsDriver.getNews = getNewsMock

    const convertNewsMock = jest.fn()
    when(convertNewsMock).calledWith(newsEntity).defaultReturnValue(news)
    newsGateway['convertNews'] = convertNewsMock

    const actual = await newsGateway.getNews()

    expect(actual).toEqual(news)
    expect(newsDriver.getNews).nthCalledWith(1)
    expect(newsGateway['convertNews']).nthCalledWith(1, newsEntity)
  })
})

 ...</pre><p>&nbsp;</p>
<p>convertNewsの単体テストにおいて、Newsドメインにファクトリメソッドであるfromメソッドをmockする方法がわかりました。</p><pre class="crayon-plain-tag">private convertNews(newsEntity: NewsEntity[]): News {
  const news = News.from(newsEntity)

  return news
}</pre><p></p><pre class="crayon-plain-tag">...

describe('convertNews', () =&gt; {
  it('ニュースドメインに変換することができる', async () =&gt; {
    const newsEntity = mock&lt;NewsEntity[]&gt;()
    const news= mock&lt;News&gt;()
    const from = jest.spyOn(News, 'from')
      .mockImplementation((_: NewsEntity[]): News =&gt; {
          return news;
      })

    const actual = newsGateway['convertNews'](newsEntity)

    expect(actual).toEqual(news)
    expect(from).toBeCalled()
  })
})

...
</pre><p>まずspyOnでNewsドメインのfromメソッドをmockします。mockImplementation() 関数の引数は、以下のようになっています。</p>
<ul>
<li>第1引数：モックするメソッドの引数型</li>
<li>第2引数：モックするメソッドの戻り値型</li>
<li>第3引数：モックするメソッドの処理本体</li>
</ul>
<p>この場合、第1引数は NewsEntity[] 型、第2引数はNews型、第3引数はNews型のオブジェクトを返す処理です。つまり、from() メソッドにNewsEntity[]型のエンティティを渡すと、常にnewsを返すように設定しています。</p>
<p>convertNewsはprivateメソッドなので、newsEntityを引数rにnewsGateway[&#8216;convertNews&#8217;]の形で呼び出します。</p>
<p>あとは結果が正しいかと、mockしたfromメソッドが呼び出されたかを確認しています。</p>The post <a href="https://mintaku-blog.net/mock-static/">ドメインのstaticメソッドをmockする</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></content:encoded>
					
					<wfw:commentRss>https://mintaku-blog.net/mock-static/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2442</post-id>	</item>
		<item>
		<title>【Nuxt.js】JestでTDDを実践してみる</title>
		<link>https://mintaku-blog.net/jest-tdd/</link>
					<comments>https://mintaku-blog.net/jest-tdd/#respond</comments>
		
		<dc:creator><![CDATA[みんたく]]></dc:creator>
		<pubDate>Sun, 27 Jun 2021 13:42:53 +0000</pubDate>
				<category><![CDATA[Vue.js]]></category>
		<category><![CDATA[Nuxt.js]]></category>
		<category><![CDATA[TDD]]></category>
		<guid isPermaLink="false">https://mintaku-blog.net/?p=2013</guid>

					<description><![CDATA[<p>JestでTDDを実践しながらNuxt.jsで簡単なToDoリストをつくってみました。 ToDoリストのストーリーを考える Nuxt.jsで簡単なToDoリ …</p>
The post <a href="https://mintaku-blog.net/jest-tdd/">【Nuxt.js】JestでTDDを実践してみる</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></description>
										<content:encoded><![CDATA[<p>JestでTDDを実践しながらNuxt.jsで簡単なToDoリストをつくってみました。</p>
<h2>ToDoリストのストーリーを考える</h2>
<p>Nuxt.jsで簡単なToDoリストをつくりにあたり、ユーザーストーリーを考えます。考えた結果、以下のストーリーができました。</p>
<ul>
<li>ユーザーはフォームと作成ボタンを見ることができる</li>
<li>ユーザーはToDoタスク一覧と完了タスク一覧を見ることができる</li>
<li>ユーザーはフォームにタスクを入力して作成ボタンを押すと、ToDoタスク一覧に追加されることを確認できる</li>
<li>ユーザーはフォームにタスクが入力していない場合は、作成ボタンを押すことができない</li>
<li>ユーザーはToDoタスクの完了ボタンを押すと、完了タスク一覧にタスクが移動されることを確認できる</li>
<li>ユーザーは完了タスクのToDoに戻すボタンを押すと、ToDoタスク一覧にタスクが移動されることを確認できる</li>
</ul>
<p>ToDoリストの画面は、TaskFormコンポーネントとTaskListコンポーネントに分けて実装します。</p>
<p>またタスクのデータはFirestoreに格納するようにし、REST APIでデータを操作します。</p>
<p>Nuxt.jsやJestのインストールやFirestoreのセットアップなどは省略しています。</p>
<p>&nbsp;</p>
<h2>「ユーザーはフォームと作成ボタンを見ることができる」のテストを書く</h2>
<p>まず「ユーザーはフォームと作成ボタンを見ることができる」のテストを書いていきます。</p>
<p>TaskFormコンポーネントを作成し、タスク入力フォームと作成ボタンが存在することをチェックします。</p>
<p>・components/TaskForm.spec.js</p><pre class="crayon-plain-tag">import { mount } from '@vue/test-utils'
import TaskForm from '@/components/TaskForm.vue'

describe('components/TaskForm.vue', () =&gt; {
  let wrapper
  beforeEach(() =&gt; {
    wrapper = mount(TaskForm)
  })

  describe('template', () =&gt; {
    test('タスク入力フォームが存在すること', () =&gt; {
      const form = wrapper.find('input');
      expect(form.exists()).toBe(true);
    })

    test('タスク作成ボタンが存在すること', () =&gt; {
      const button = wrapper.find('input');
      expect(button.exists()).toBe(true);
   })
  })
})</pre><p>テストを作成したら実際にテストを実行してみます。TDDでいうレッドのところです。</p>
<p>まだ実装はしていないので全部のテストが失敗しますが、期待通りの落ち方をしているかを確認します。</p><pre class="crayon-plain-tag">FAIL  components/TaskForm.spec.js
  components/TaskForm.vue
    template
      ✕ タスク入力フォームが存在すること (10 ms)
      ✕ タスク作成ボタンが存在すること (1 ms)

  ● components/TaskForm.vue &gt; template &gt; タスク入力フォームが存在すること

    expect(received).toBe(expected) // Object.is equality

    Expected: true
    Received: false

      16 |     test('タスク入力フォームが存在すること', () =&gt; {
      17 |       const form = wrapper.find('input');
    &gt; 18 |       expect(form.exists()).toBe(true);
         |                             ^
      19 |     })
      20 |
      21 |     test('タスク作成ボタンが存在すること', () =&gt; {

      at Object.&lt;anonymous&gt; (components/TaskForm.spec.js:18:29)

  ● components/TaskForm.vue &gt; template &gt; タスク作成ボタンが存在すること

    expect(received).toBe(expected) // Object.is equality

    Expected: true
    Received: false

      21 |     test('タスク作成ボタンが存在すること', () =&gt; {
      22 |       const button = wrapper.find('input');
    &gt; 23 |       expect(button.exists()).toBe(true);
         |                               ^
      24 |     })
      25 |
      26 |   })

      at Object.&lt;anonymous&gt; (components/TaskForm.spec.js:23:31)</pre><p>存在していない、実装されていないなどの落ち方をしていればひとまず完了です。</p>
<p>&nbsp;</p>
<h2>「ユーザーはフォームと作成ボタンを見ることができる」を実装する</h2>
<p>テストで書いたシナリオを元にTaskFormコンポーネントを実装してきます。今回は簡易的なHTMLでフォームとボタンを作成しました。</p>
<p>・components/TaskForm.vue</p><pre class="crayon-plain-tag">&lt;template&gt;
  &lt;div&gt;
    &lt;input&gt;
    &lt;button&gt;
      タスク作成
    &lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;</pre><p>&nbsp;</p>
<h2>「ユーザーはフォームと作成ボタンを見ることができる」をテストする</h2>
<p>実装が終わったら、再度TaskFormのテストを流してみます。TDDでいうグリーンのところです。</p>
<p>テストが全て通ったらこのストーリーの実装は完了です。必要に応じてリファクタリングをします。</p><pre class="crayon-plain-tag">PASS  components/TaskForm.spec.js
  components/TaskForm.vue
    template
      ✓ タスク入力フォームが存在すること (9 ms)
      ✓ タスク作成ボタンが存在すること (1 ms)</pre><p>&nbsp;</p>
<h2>「ユーザーはToDoタスク一覧と完了タスク一覧を見ることができる」のテストを書く</h2>
<p>次に「ユーザーはToDoタスク一覧と完了タスク一覧を見ることができる」のテストを書いていきます。</p>
<p>TaskListコンポーネントでToDoリストと完了リストを表示するようにします。</p>
<p>そのため、ToDoリストと完了リストにFirestoreに格納されているデータをfetchしてくるようにします。</p>
<p>・components/TaskList.spec.js</p><pre class="crayon-plain-tag">import Vuex from 'vuex'
import { mount, createLocalVue} from '@vue/test-utils'
import * as indexStore from '@/store'
import TaskList from '@/components/TaskList.vue'

const localVue = createLocalVue()
localVue.use(Vuex)

describe('components/TaskList.vue', () =&gt; {
  let wrapper
  let store
  let todoTask
  let doneTask
  beforeEach(() =&gt; {
    store = new Vuex.Store(indexStore)
    todoTask = { id: '1', content: 'content_1', status: 'todo' }
    doneTask = { id: '2', content: 'content_2', status: 'done' }
    wrapper = mount(TaskList, {
      store: store,
      localVue
    })
    store.replaceState({ tasks: [todoTask, doneTask] })
  })

  describe('template', () =&gt; {
    test('todoリストが表示されること', () =&gt; {
      const li = wrapper.find('li.todo')
      expect(li.find('span').text()).toBe(todoTask.content)
      expect(li.find('button).text()).toBe('完了')
    })

    test('完了リストが表示されること', () =&gt; {
      const li = wrapper.find('li.done')
      expect(li.find('span').text()).toBe(doneTask.content)
      expect(li.find('button).text()).toBe('ToDoに戻す')
    })
  })

  describe('script', () =&gt; {
    describe('computed', () =&gt; {
      describe('todos', () =&gt; {
        test('storeからtodoTasksが取得できること', () =&gt; {
          expect(wrapper.vm.todoTasks).toEqual(expect.arrayContaining([todoTask]))
        })
        test('storeからdoneTasksが取得できること', () =&gt; {
          expect(wrapper.vm.doneTasks).toEqual(expect.arrayContaining([doneTask]))
        })
      })
    })
  })
})</pre><p>タスクリストの状態管理をするストアのテストを書きます。</p>
<p>ステータスの状態によってToDoタスクと完了タスクを出し分けるようにします。</p>
<p>Storeではaxiosを使って外部サービスにHTTPリクエストしているためaxiosをモック化してテストしています。</p>
<p>async/awaitでaxiosの非同期処理を実現し、結果をgettersから取り出し比較します。</p>
<p>参考：https://github.com/nuxt-community/axios-module/issues/105</p>
<p>・store/index.spec.js</p><pre class="crayon-plain-tag">import Vuex from 'vuex'
import * as index from '@/store'
import { createLocalVue } from '@vue/test-utils'
import _ from 'lodash'
import axios from 'axios'

const localVue = createLocalVue()
localVue.use(Vuex)

let mockAxiosGetResult
jest.mock('axios', () =&gt; ({
  get: jest.fn(() =&gt; Promise.resolve(mockAxiosGetResult))
}))

let action
const testedAction = (context = {}, payload = {}) =&gt; {
  return index.actions[action].bind({ $axios: axios })(context, payload)
}

describe('store/index.js', () =&gt; {
  let store
  let todoTask, doneTask
  beforeEach(() =&gt; {
    store = new Vuex.Store(_.cloneDeep(index))
    todoTask = { id: '1', content: 'content_1', status: 'todo' }
    doneTask = { id: '2', content: 'content_2', status: 'done' }
  })

  describe('getters', () =&gt; {
    let tasks
    let todoTasks
    let doneTasks
    beforeEach(() =&gt; {
      tasks = [todoTask, doneTask]
      todoTasks = [todoTask]
      doneTasks = [doneTask]
      store.replaceState({
        tasks,
        todoTasks,
        doneTasks
      })
    })

    describe('todoTasks', () =&gt; {
      test('statusがtodoのtaskが取得できること', () =&gt; {
        expect(store.getters['todoTasks']).toContainEqual(todoTask)
        expect(store.getters['todoTasks']).not.toContainEqual(doneTask)
      })
    })
    describe('doneTasks', () =&gt; {
      test('statusがdoneのtaskが取得できること', () =&gt; {
        expect(store.getters['doneTasks']).not.toContainEqual(todoTask)
        expect(store.getters['doneTasks']).toContainEqual(doneTask)
      })
    })
    describe('tasks', () =&gt; {
      test('すべてのtasksが取得できること', () =&gt; {
        expect(store.getters['tasks']).toEqual(
          expect.arrayContaining(tasks)
        )
      })
    })
  })

  describe('actions', () =&gt; {
    let commit
    beforeEach(() =&gt; {
      commit = store.commit
    })

    describe('fetchTasks', () =&gt; {
      test('tasksが取得できること', async () =&gt; {
        action = 'fetchTasks'
        mockAxiosGetResult = {
          data: {
            documents: [
              {
                name: `tasks/${todoTask.id}`,
                fields: {
                  content: { stringValue: todoTask.content },
                  status: { stringValue: todoTask.status }
                }
              },
              {
                name: `tasks/${doneTask.id}`,
                fields: {
                  content: { stringValue: doneTask.content },
                  status: { stringValue: doneTask.status }
                }
              }
            ]
          }
        }

        await testedAction({ commit })
        expect(store.getters['tasks']).toEqual([todoTask, doneTask])
      })
    })
  })
})</pre><p>テスト結果を省略していますが、ここでまたテストを実行し期待通りに落ちているかを確認します。</p>
<p>&nbsp;</p>
<h2>「ユーザーはToDoタスク一覧と完了タスク一覧を見ることができる」を実装する</h2>
<p>テストが書いたシナリオを元にTaskListコンポーネントとindexページ、indexストアを実装してきます。</p>
<p>TaskListコンポーネントではToDoリストと完了リストがあり、indexページではTaskListコンポーネントとTaskFormコンポーネントを呼び出してタスクをストアから呼び出すようにします。</p>
<p>indexストアではFirestoreからデータを取ってきてToDoタスクと完了タスクに状態管理するようにします。</p>
<p>・components/TaskList.vue</p><pre class="crayon-plain-tag">&lt;template&gt;
  &lt;div&gt;
    &lt;p&gt;ToDoリスト&lt;/p&gt;
    &lt;ul&gt;
      &lt;li
        v-for="todoTask in todoTasks"
        :key="todoTask.id"
        class="todo"
      &gt;
        &lt;span&gt;{{ todoTask.content }}&lt;/span&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
    &lt;hr&gt;
    &lt;p&gt;完了リスト&lt;/p&gt;
    &lt;ul&gt;
      &lt;li
        v-for="doneTask in doneTasks"
        :key="doneTask.id"
        class="done"
      &gt;
        &lt;span&gt;{{ doneTask.content }}&lt;/span&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import { mapGetters } from 'vuex'
import _ from 'lodash'

export default {
  computed: {
    ...mapGetters(['todoTasks']),
    ...mapGetters(['doneTasks'])
  }
}
&lt;/script&gt;</pre><p>・pages/index.vue</p><pre class="crayon-plain-tag">&lt;template&gt;
  &lt;section&gt;
    &lt;TaskForm/&gt;
    &lt;TaskList/&gt;
  &lt;/section&gt;
&lt;/template&gt;

&lt;script&gt;
import TaskForm from '@/components/TaskForm.vue'
import TaskList from '@/components/TaskList.vue'

export default {
  async asyncData({ store }) {
    await store.dispatch('fetchTasks')
  },
  components: {
    TaskForm,
    TaskList
  }
}
&lt;/script&gt;</pre><p><span style="font-weight: 400;">・store/index.spec.js</span></p><pre class="crayon-plain-tag">import _ from 'lodash'

export const state = () =&gt; ({
  tasks: []
})

export const getters = {
  tasks: state =&gt; state.tasks,
  todoTasks: state =&gt; state.tasks.filter(task =&gt; task.status === 'todo'),
  doneTasks: state =&gt; state.tasks.filter(task =&gt; task.status === 'done')
}

export const mutations = {
  updateTasks(state, tasks) {
    state.tasks = tasks
  }
}

export const actions = {
  async fetchTasks({ commit }) {
    await this.$axios.get(`/tasks`, {
      baseURL: process.env._AXIOS_BASE_URL_
    })
      .then(res =&gt; {
      let tasks = []
      if (_.has(res.data, 'documents')) {
        tasks = res.data.documents.map(doc =&gt; {
          return {
            id: _.last(doc.name.split('/')),
            content: doc.fields.content.stringValue,
            status: doc.fields.status.stringValue
          }
        })
      }
      commit('updateTasks', tasks)
    })
  }
}</pre><p>&nbsp;</p>
<h2>「ユーザーはToDoタスク一覧と完了タスク一覧を見ることができる」をテストする</h2>
<p>実装が終わったら再度テストを流します。テストが全て通ればこのストーリーは完了です。</p><pre class="crayon-plain-tag">PASS  components/TaskList.spec.js
  components/TaskList.vue
    template
      ✓ todoリストが表示されること (13 ms)
      ✓ 完了リストが表示されること (2 ms)
    script
      computed
        todos
          ✓ storeからtodoTasksが取得できること (2 ms)
          ✓ storeからdoneTasksが取得できること (1 ms)</pre><p></p><pre class="crayon-plain-tag">PASS  store/index.spec.js
  store/index.js
    getters
      todoTasks
        ✓ statusがtodoのtaskが取得できること (3 ms)
      doneTasks
        ✓ statusがdoneのtaskが取得できること (1 ms)
      tasks
        ✓ すべてのtasksが取得できること (1 ms)
    actions
      fetchTasks
        ✓ tasksが取得できること</pre><p>&nbsp;</p>
<h2>「ユーザーはフォームにタスクを入力して作成ボタンを押すと、ToDoタスク一覧に追加されることを確認できる」のテストを書く</h2>
<p>先ほどTaskFormコンポーネントに作成したフォームに入力して作成ボタンを押すとToDoタスク一覧に追加されることが確認できるテストを書きます。</p>
<p>・components/TaskForm.spec.js</p><pre class="crayon-plain-tag">import Vuex from 'vuex'
import { mount, createLocalVue } from '@vue/test-utils'
import * as store from '@/store'
import TaskForm from '@/components/TaskForm.vue'

const localVue = createLocalVue()
localVue.use(Vuex)

describe('components/TaskForm.vue', () =&gt; {
  let wrapper
  beforeEach(() =&gt; {
    wrapper = mount(TaskForm, {
      store: store,
      localVue
    })
  })

  describe('template', () =&gt; {
    
...

    describe('タスク入力がある場合', () =&gt; {
      beforeEach(() =&gt; {
        const mock = jest.fn()
        wrapper.vm.addTask = mock
        wrapper.find('input').setValue('content')
      })

      test('dataに入力が反映されること', () =&gt; {
        expect(wrapper.vm.taskForm.content).toBe('content')
      })

      test('タスク作成ボタンを押下するとaddTaskが呼ばれること', () =&gt; {
        wrapper.find('button').trigger('click')
        
        expect(wrapper.vm.addTask).toHaveBeenCalled()
      })
    })
  })

  describe('script', () =&gt; {
    describe('data', () =&gt; {
      test('dataの構造が正しいこと', () =&gt; {
        expect(wrapper.vm.$data).toHaveProperty('taskForm.content')
      })
    })
  })
})</pre><p>ストアのテストでは作成ボタンが押下された際にFirestoreに入力されたタスクのデータが保存されることを確認します。</p>
<p>・store/index.spec.js</p><pre class="crayon-plain-tag">import Vuex from 'vuex'
import * as index from '@/store'
import { createLocalVue } from '@vue/test-utils'
import _ from 'lodash'
import axios from 'axios'

const localVue = createLocalVue()
localVue.use(Vuex)

let mockAxiosGetResult
jest.mock('axios', () =&gt; ({
  
...

  post: jest.fn(() =&gt; Promise.resolve(mockAxiosGetResult))
}))

let action
const testedAction = (context = {}, payload = {}) =&gt; {
  return index.actions[action].bind({ $axios: axios })(context, payload)
}

describe('store/index.js', () =&gt; {

...

  describe('actions', () =&gt; {
    let commit
    beforeEach(() =&gt; {
      commit = store.commit
    })

...

    describe('createTask', () =&gt; {
      test('taskが追加されること', async () =&gt; {
        mockAxiosGetResult = {
          data: {
            name: `tasks/${todoTask.id}`,
            fields: {
              content: { stringValue: todoTask.content },
              status: { stringValue: todoTask.status }
            }
          }
        }
        action = 'createTask'
        await testedAction({ commit })
        expect(store.getters['todoTasks']).toContainEqual(todoTask)
      })
    })
  })
})</pre><p>&nbsp;</p>
<h2>「ユーザーはフォームにタスクを入力して作成ボタンを押すと、ToDoタスク一覧に追加されることを確認できる」を実装する</h2>
<p>タスク作成ボタンが押されるとaddTaskが呼び出されるように実装していきます。</p>
<p>addTaskメソッドはストアのcreateTaskを呼び出し、タスクが状態管理されるようにします。</p>
<p>・components/TaskForm.vue</p><pre class="crayon-plain-tag">&lt;template&gt;
  &lt;div&gt;
    &lt;input
      v-model="taskForm.content"
    &gt;
    &lt;button
      @click="addTask"&gt;
      タスク作成
    &lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import _ from 'lodash'

export default {
  data() {
    return {
      taskForm: { content: '' }
    }
  },
  methods: {
    async addTask() {
        await this.$store.dispatch('createTask', _.cloneDeep(this.taskForm))
        this.taskForm.content = ''
    }
  }
}
&lt;/script&gt;</pre><p>addTaskから呼びだされるcreateTaskの実装をストアに書いていきます。</p>
<p>・store/index.js</p><pre class="crayon-plain-tag">import _ from 'lodash'

export const state = () =&gt; ({
  tasks: []
})

export const getters = {
  tasks: state =&gt; state.tasks,

...

}

export const mutations = {

  ...

  addTask(state, newTask) {
    state.tasks.push(newTask)
  }

...

}

export const actions = {
  async createTask({ commit }, payload) {
    const req = {
      fields: {
        content: {
          stringValue: payload.content
        },
        status: {
          stringValue: 'todo'
        }
      }
    }
    await this.$axios.post('/tasks', req, {
      baseURL: process.env._AXIOS_BASE_URL_
    }).then(res =&gt; {
      const newTask = {
        id: _.last(res.data.name.split('/')),
        content: res.data.fields.content.stringValue,
        status: res.data.fields.status.stringValue
      }
      commit('addTask', newTask)
    })
  }
 }</pre><p>&nbsp;</p>
<h2>「ユーザーはフォームにタスクを入力して作成ボタンを押すと、ToDoタスク一覧に追加されることを確認できる」をテストする</h2>
<p>実装が終わったら再度テストを流します。テストが全て通ればこのストーリーは完了です。</p><pre class="crayon-plain-tag">PASS  components/TaskForm.spec.js
  components/TaskForm.vue
    template
      ✓ タスク入力フォームが存在すること (11 ms)
      ✓ タスク作成ボタンが存在すること (6 ms)
      タスク入力がある場合
        ✓ dataに入力が反映されること (3 ms)
        ✓ タスク作成ボタンを押下するとaddTaskが呼ばれること (2 ms)
    script
      data
        ✓ dataの構造が正しいこと (1 ms)</pre><p></p><pre class="crayon-plain-tag">PASS  store/index.spec.js
  store/index.js
    getters
      todoTasks
        ✓ statusがtodoのtaskが取得できること (3 ms)
      doneTasks
        ✓ statusがdoneのtaskが取得できること (1 ms)
      tasks
        ✓ すべてのtasksが取得できること (1 ms)
    actions
      fetchTasks
        ✓ tasksが取得できること (1 ms)
      createTask
        ✓ taskが追加されること (1 ms)</pre><p>&nbsp;</p>
<h2>「ユーザーはフォームにタスクが入力していない場合は、作成ボタンを押すことができない」のテストを書く</h2>
<p>フォームにタスクが入力していない場合は、作成ボタンを押すことができないことを確認できるテストを書いていきます。</p>
<p>・components/TaskForm.spec.js</p><pre class="crayon-plain-tag">import Vuex from 'vuex'
import { mount, createLocalVue } from '@vue/test-utils'
import * as store from '@/store'
import TaskForm from '@/components/TaskForm.vue'

const localVue = createLocalVue()
localVue.use(Vuex)

describe('components/TaskForm.vue', () =&gt; {
  let wrapper
  beforeEach(() =&gt; {
    wrapper = mount(TaskForm, {
      store: store,
      localVue
    })
  })


  describe('template', () =&gt; {

    ...

    describe('タスク入力がない場合', () =&gt; {
      beforeEach(() =&gt; {
        const mock = jest.fn()
        wrapper.vm.addTask = mock
        wrapper.find('input').setValue('')
      })

      test('dataに入力が反映されること', () =&gt; {
        expect(wrapper.vm.taskForm.content).toBe('')
      })

      test('タスク作成ボタンを押下するとaddTaskが呼ばれないこと', () =&gt; {
        wrapper.find('button').trigger('click')
        
        expect(wrapper.vm.addTask).not.toHaveBeenCalled()
      })
    })
  
  })

 ...

})</pre><p>&nbsp;</p>
<h2>「ユーザーはフォームにタスクが入力していない場合は、作成ボタンを押すことができない」を実装する</h2>
<p>ボタンにdisabled属性を付与し、computedでフォームの入力を監視してボタンの活性非活性を制御するように実装しました。</p>
<p>・components/TaskForm.vue</p><pre class="crayon-plain-tag">&lt;template&gt;
  &lt;div&gt;
    &lt;input
      v-model="taskForm.content"
    &gt;
    &lt;button
      :disabled="activateSubmit"
      @click="addTask"&gt;
      タスク作成
    &lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import _ from 'lodash'

export default {
  
...

  computed: {
    activateSubmit () {
      return this.taskForm.content == ''
    }
  },
  
...

}
&lt;/script&gt;</pre><p>&nbsp;</p>
<h2>「ユーザーはフォームにタスクが入力していない場合は、作成ボタンを押すことができない」をテストする</h2>
<p>実装が終わったら再度テストを流します。テストが全て通ればこのストーリーは完了です。</p><pre class="crayon-plain-tag">PASS  components/TaskForm.spec.js
  components/TaskForm.vue
    template
      ✓ タスク入力フォームが存在すること (9 ms)
      ✓ タスク作成ボタンが存在すること (1 ms)
      タスク入力がある場合
        ✓ dataに入力が反映されること (2 ms)
        ✓ タスク作成ボタンを押下するとaddTaskが呼ばれること (2 ms)
      タスク入力がない場合
        ✓ dataに入力が反映されること (1 ms)
        ✓ タスク作成ボタンを押下するとaddTaskが呼ばれないこと (1 ms)
    script
      data
        ✓ dataの構造が正しいこと (1 ms)</pre><p>&nbsp;</p>
<h2>「ユーザーはToDoタスクの完了ボタンを押すと、完了タスク一覧にタスクが移動されることを確認できる」のテストを書く</h2>
<p>ToDoタスクの完了ボタンを押すと、完了タスク一覧にタスクが移動されることを確認できるテストを書いていきます。</p>
<p>・components/TaskList.spec.js</p><pre class="crayon-plain-tag">import Vuex from 'vuex'
import { mount, createLocalVue } from '@vue/test-utils'
import * as indexStore from '@/store'
import TaskList from '@/components/TaskList.vue'

const localVue = createLocalVue()
localVue.use(Vuex)

describe('components/TaskList.vue', () =&gt; {
  let wrapper
  let store
  let todoTask
  let doneTask
  beforeEach(() =&gt; {
    store = new Vuex.Store(indexStore)
    todoTask = { id: '1', content: 'content_1', status: 'todo' }
    doneTask = { id: '2', content: 'content_2', status: 'done' }
    wrapper = mount(TaskList, {
      store: store,
      localVue
    })
    store.replaceState({ tasks: [todoTask, doneTask] })
  })

  describe('template', () =&gt; {
   
...

    describe('todoリストの完了をクリックする場合', () =&gt; {
      test('doneTaskが指定の引数で呼び出されること', () =&gt; {
        const mock = jest.fn(todoTask =&gt; todoTask)
        wrapper.vm.doneTask = mock
     
        wrapper.find('li.todo button').trigger('click')
        expect(wrapper.vm.doneTask).toHaveBeenCalled()
        expect(wrapper.vm.doneTask.mock.results[0].value).toBe(todoTask)
      })
    })
  })

  ...

})</pre><p>ストアではタスクのステータスが更新されることが確認できるテストを書いていきます。</p>
<p>・store/index.spec.js</p><pre class="crayon-plain-tag">import Vuex from 'vuex'
import * as index from '@/store'
import { createLocalVue } from '@vue/test-utils'
import _ from 'lodash'
import axios from 'axios'

const localVue = createLocalVue()
localVue.use(Vuex)

let mockAxiosGetResult
jest.mock('axios', () =&gt; ({
  
...

  patch: jest.fn(() =&gt; Promise.resolve(mockAxiosGetResult))
}))

let action
const testedAction = (context = {}, payload = {}) =&gt; {
  return index.actions[action].bind({ $axios: axios })(context, payload)
}

describe('store/index.js', () =&gt; {
  let store
  let todoTask, doneTask
  beforeEach(() =&gt; {
    store = new Vuex.Store(_.cloneDeep(index))
    todoTask = { id: '1', content: 'content_1', status: 'todo' }
    doneTask = { id: '2', content: 'content_2', status: 'done' }
  })


...

  describe('actions', () =&gt; {
    let commit
    beforeEach(() =&gt; {
      commit = store.commit
    })

   ...

    describe('updateTask', () =&gt; {
      beforeEach(() =&gt; {
        store.replaceState({
          tasks: [todoTask]
        })
      })

      test('taskが更新されること', async () =&gt; {
        mockAxiosGetResult = {
          data: {
            name: `tasks/${todoTask.id}`,
            fields: {
              content: { stringValue: 'updatedContent' },
              status: { stringValue: 'done' }
            }
          }
        }
        action = 'updateTask'
        await testedAction({ commit })
        expect(store.getters['doneTasks']).toContainEqual({
          id: todoTask.id,
          content: 'updatedContent',
          status: 'done'
        })
      })
    })
  })
})</pre><p>&nbsp;</p>
<h2>「ユーザーはToDoタスクの完了ボタンを押すと、完了タスク一覧にタスクが移動されることを確認できる」を実装する</h2>
<p>ToDoタスクの完了ボタンを押すと、ストアのupdateTaskを呼び出しステータスを完了にすることで完了タスク一覧に移動されるように実装します。</p>
<p>・components/TaskList.vue</p><pre class="crayon-plain-tag">&lt;template&gt;
  &lt;div&gt;
    &lt;p&gt;ToDoタスク&lt;/p&gt;
    &lt;ul&gt;
      &lt;li
        v-for="todoTask in todoTasks"
        :key="todoTask.id"
        class="todo"
      &gt;
        &lt;span&gt;{{ todoTask.content }}&lt;/span&gt;
        &lt;button 
          @click="doneTask(todoTask)"&gt;
          完了
        &lt;/button&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
    &lt;hr&gt;
    &lt;p&gt;完了タスク&lt;/p&gt;
    &lt;ul&gt;
      &lt;li
        v-for="doneTask in doneTasks"
        :key="doneTask.id"
        class="done"
      &gt;
        &lt;span&gt;{{ doneTask.content }}&lt;/span&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import { mapGetters } from 'vuex'
import _ from 'lodash'

export default {
  
...

  methods: {
    async doneTask(task) {
      const payload = _.cloneDeep(task)
      payload.status = 'done'
      await this.$store.dispatch('updateTask', payload)
    }
  }
}
&lt;/script&gt;</pre><p>・store/index.js</p><pre class="crayon-plain-tag">import _ from 'lodash'

export const state = () =&gt; ({
  tasks: []
})

export const getters = {
  tasks: state =&gt; state.tasks,

  ...

}

export const mutations = {
  
...

  updateTask(state, newTask) {
    const task = state.tasks.find(task =&gt; task.id === newTask.id)
    if (task) {
      task.content = newTask.content
      task.status = newTask.status
    }
  }
}

export const actions = {
 
...

  async updateTask({ commit }, payload) {
    const req = {
      fields: {
        content: {
          stringValue: payload.content
        },
        status: {
          stringValue: payload.status
        }
      }
    }
    await this.$axios.patch(`/tasks/${payload.id}`, req, {
      baseURL: process.env._AXIOS_BASE_URL_
    }).then(res =&gt; {
      const updateTask = {
        id: _.last(res.data.name.split('/')),
        content: res.data.fields.content.stringValue,
        status: res.data.fields.status.stringValue
      }
      commit('updateTask', updateTask)
    })
  }
}</pre><p>&nbsp;</p>
<h2>「ユーザーはToDoタスクの完了ボタンを押すと、完了タスク一覧にタスクが移動されることを確認できる」のテストをする</h2>
<p>実装が終わったら再度テストを流します。テストが全て通ればこのストーリーは完了です。</p><pre class="crayon-plain-tag">PASS  components/TaskList.spec.js
  components/TaskList.vue
    template
      ✓ todoリストが表示されること (17 ms)
      ✓ 完了リストが表示されること (2 ms)
      todoリストの完了をクリックする場合
        ✓ doneTaskが指定の引数で呼び出されること (3 ms)
    script
      computed
        todos
          ✓ storeからtodoTasksが取得できること (1 ms)
          ✓ storeからdoneTasksが取得できること (2 ms)</pre><p></p><pre class="crayon-plain-tag">PASS  store/index.spec.js
  store/index.js
    getters
      todoTasks
        ✓ statusがtodoのtaskが取得できること (3 ms)
      doneTasks
        ✓ statusがdoneのtaskが取得できること (1 ms)
      tasks
        ✓ すべてのtasksが取得できること
    actions
      fetchTasks
        ✓ tasksが取得できること (1 ms)
      createTask
        ✓ taskが追加されること
      updateTask
        ✓ taskが更新されること</pre><p>&nbsp;</p>
<h2>「ユーザーは完了タスクのToDoに戻すボタンを押すと、ToDoタスク一覧にタスクが移動されることを確認できる」のテストを書く</h2>
<p>完了タスクのToDoに戻すボタンを押すと、ToDoタスク一覧にタスクが移動されることを確認できることが確認できるテストを書いていきます。</p>
<p>ストアのタスクステータス更新のテストは先程のストーリーで確認済みなため、新しくストアのテストは書いていません。</p>
<p>・components/TaskList.spec.js</p><pre class="crayon-plain-tag">import Vuex from 'vuex'
import { mount, createLocalVue } from '@vue/test-utils'
import * as indexStore from '@/store'
import TaskList from '@/components/TaskList.vue'

const localVue = createLocalVue()
localVue.use(Vuex)

describe('components/TaskList.vue', () =&gt; {
  let wrapper
  let store
  let todoTask
  let doneTask
  beforeEach(() =&gt; {
    store = new Vuex.Store(indexStore)
    todoTask = { id: '1', content: 'content_1', status: 'todo' }
    doneTask = { id: '2', content: 'content_2', status: 'done' }
    wrapper = mount(TaskList, {
      store: store,
      localVue
    })
    store.replaceState({ tasks: [todoTask, doneTask] })
  })

  describe('template', () =&gt; {
   
...

   describe('完了リストのToDoに戻すをクリックする場合', () =&gt; {
      test('returnTaskが指定の引数で呼び出されること', () =&gt; {
        const mock = jest.fn(doneTask =&gt; doneTask)
        wrapper.vm.returnTask = mock
     
        wrapper.find('li.done button').trigger('click')
        expect(wrapper.vm.returnTask).toHaveBeenCalled()
        expect(wrapper.vm.returnTask.mock.results[0].value).toBe(doneTask)
      })
    })
 })

  ...

})</pre><p>&nbsp;</p>
<h2>「ユーザーは完了タスクのToDoに戻すボタンを押すと、ToDoタスク一覧にタスクが移動されることを確認できる」を実装する</h2>
<p>完了タスクのToDoに戻すボタンを押すと、ストアのupdateTaskを呼び出しステータスをToDoにすることでToDoタスク一覧に移動されるように実装します。</p>
<p>・components/TaskList.vue</p><pre class="crayon-plain-tag">&lt;template&gt;
  &lt;div&gt;
    &lt;p&gt;ToDoタスク&lt;/p&gt;
    &lt;ul&gt;
      &lt;li
        v-for="todoTask in todoTasks"
        :key="todoTask.id"
        class="todo"
      &gt;
        &lt;span&gt;{{ todoTask.content }}&lt;/span&gt;
        &lt;button 
          @click="doneTask(todoTask)"&gt;
          完了
        &lt;/button&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
    &lt;hr&gt;
    &lt;p&gt;完了タスク&lt;/p&gt;
    &lt;ul&gt;
      &lt;li
        v-for="doneTask in doneTasks"
        :key="doneTask.id"
        class="done"
      &gt;
        &lt;span&gt;{{ doneTask.content }}&lt;/span&gt;
        &lt;button 
          @click="returnTask(doneTask)"&gt;
          ToDoに戻す
        &lt;/button&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import { mapGetters } from 'vuex'
import _ from 'lodash'

export default {

...

  methods: {

    ...

    async returnTask(task) {
      const payload = _.cloneDeep(task)
      payload.status = 'todo'
      await this.$store.dispatch('updateTask', payload)
    }
  }
}
&lt;/script&gt;</pre><p>&nbsp;</p>
<h2>「ユーザーは完了タスクのToDoに戻すボタンを押すと、ToDoタスク一覧にタスクが移動されることを確認できる」のテストをする</h2>
<p>実装が終わったら再度テストを流します。テストが全て通ればこのストーリーは完了です。</p><pre class="crayon-plain-tag">PASS  components/TaskList.spec.js
  components/TaskList.vue
    template
      ✓ todoリストが表示されること (12 ms)
      ✓ 完了リストが表示されること (3 ms)
      todoリストの完了をクリックする場合
        ✓ doneTaskが指定の引数で呼び出されること (3 ms)
      完了リストのToDoに戻すをクリックする場合
        ✓ returnTaskが指定の引数で呼び出されること (2 ms)
    script
      computed
        todos
          ✓ storeからtodoTasksが取得できること (1 ms)
          ✓ storeからdoneTasksが取得できること (5 ms)</pre><p>&nbsp;</p>
<h2>全部のテストを流す</h2>
<p>全部の実装が終わったら、全てのテストを流します。package.jsonのscriptに&#8221;test&#8221;: &#8220;jest &#8211;config jest.config.js&#8221;を追加し、以下のコマンドで実行します。</p><pre class="crayon-plain-tag">$ npm run test

PASS components/TaskForm.spec.js
PASS components/TaskList.spec.js
PASS store/index.spec.js</pre><p>&nbsp;</p>
<p>全てのテストが通ったら完了です。</p>The post <a href="https://mintaku-blog.net/jest-tdd/">【Nuxt.js】JestでTDDを実践してみる</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></content:encoded>
					
					<wfw:commentRss>https://mintaku-blog.net/jest-tdd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2013</post-id>	</item>
		<item>
		<title>テスト駆動開発入門を読んでTDDサイクルを試してみる</title>
		<link>https://mintaku-blog.net/introduction-tdd/</link>
					<comments>https://mintaku-blog.net/introduction-tdd/#respond</comments>
		
		<dc:creator><![CDATA[みんたく]]></dc:creator>
		<pubDate>Sat, 22 May 2021 01:00:56 +0000</pubDate>
				<category><![CDATA[技術本]]></category>
		<category><![CDATA[TDD]]></category>
		<guid isPermaLink="false">https://mintaku-blog.net/?p=1983</guid>

					<description><![CDATA[<p>テスト駆動開発入門を読み写経しながらTDDのサイクルを学んだことをメモしておきます。一部アジャイルサムライを読んでメモした箇所もあります。 TDDのサイクル …</p>
The post <a href="https://mintaku-blog.net/introduction-tdd/">テスト駆動開発入門を読んでTDDサイクルを試してみる</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></description>
										<content:encoded><![CDATA[<p>テスト駆動開発入門を読み写経しながらTDDのサイクルを学んだことをメモしておきます。一部アジャイルサムライを読んでメモした箇所もあります。</p>
<h2>TDDのサイクル</h2>
<p>テスト駆動開発は「レッド」「グリーン」「リファクタリング」のサイクルで回していきます。これは全てのストーリーの受け入れ条件を満たすまで繰り返します。</p>
<p>TDDにおいてまだ存在していなコードのテストを書くのに戸惑いますが、必要なコードがすでにそこにあるかのごとく書くことを意識すると良いみたいです。</p>
<h3>レッド</h3>
<p>新しいコードを書く前に、まずは失敗するテストコードを書きます。</p>
<p>新しいコードの意図をテストで示します。</p>
<h3>グリーン</h3>
<p>どんな方法でも良いのでテストが成功するコードを書きます。</p>
<p>素早くバーをグリーンに変えることが最優先になります。</p>
<h3>リファクタリング</h3>
<p>テストが成功する状態を維持しつつ簡潔・明快なコードにします。</p>
<p>持ち込んだ重複を取り除き、素早くグリーンになるようにします。</p>
<p>&nbsp;</p>
<h2>TDDのルール</h2>
<h3>失敗するテストを一つ書くまでは、新しいコードを一切書かない</h3>
<p>テストを書くということは、追加しようとしているコードの価値について真剣に考えることになり、そうすることで凝りすぎた解決策に走ることを避けることができます。</p>
<p>ここで大事なのは、本当に必要なコード以外書いてはいけないということです。</p>
<h3>危なっかしいところを全てテストする</h3>
<p>TDDでは文字通り全てをテストするわけはなく、危なっかしいところを全てテストします。</p>
<p>いかにも壊れてしまいそうな箇所や特定の条件下で特殊な挙動をする箇所がある場合、そうした意図を伝えるためにテストを書きます。</p>
<p>&nbsp;</p>
<h2>テストを作成する</h2>
<p>実際にテスト駆動開発入門を読みながらTDDを学びます。VSCodeにJavaの実行環境を構築し、実際にコードを書いてテストを実行していきます。</p>
<p>まずはテストを作成します。テスト駆動開発入門に則って5ドルを2回回すと10ドルと等しくなることをテストします。</p>
<p>・DollarTest.java</p><pre class="crayon-plain-tag">public class DollarTest {
  @Test

  public void testMultiplication() {
    Dollar five = new Dollar(5);
    five.times(2);
    assertEquals(10, five.amount);
  }
}</pre><p>&nbsp;</p>
<h2>失敗することを確認する</h2>
<p><img data-attachment-id="1988" data-permalink="https://mintaku-blog.net/introduction-tdd/image1-10/" data-orig-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image1-e1620484458615.jpg?fit=984%2C939&amp;ssl=1" data-orig-size="984,939" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="image1" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image1-e1620484458615.jpg?fit=300%2C286&amp;ssl=1" data-large-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image1-e1620484458615.jpg?fit=800%2C377&amp;ssl=1" loading="lazy" src="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image1-e1620484458615.jpg?resize=800%2C763&#038;ssl=1" alt="" width="800" height="763" class="aligncenter wp-image-1988" srcset="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image1-e1620484458615.jpg?w=984&amp;ssl=1 984w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image1-e1620484458615.jpg?resize=300%2C286&amp;ssl=1 300w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image1-e1620484458615.jpg?resize=768%2C733&amp;ssl=1 768w" sizes="(max-width: 800px) 100vw, 800px" data-recalc-dims="1" /></p>
<p>テストを作成したら、まだ実装していないので当たり前ですがテストが失敗することを確認します。ここまでがTDDサイクルで言う「レッド」であるという認識です。</p>
<p>&nbsp;</p>
<h2>テストが通るように実装する</h2>
<p>テストを作成し、失敗することを確認したら実際に処理を実装をしていきます。</p>
<p>・Dollar.java</p><pre class="crayon-plain-tag">public class Dollar {
  int amount;

  Dollar(int amount) {
  }

  void times(int multiplier) {
  }
}</pre><p>&nbsp;</p>
<p><img data-attachment-id="1985" data-permalink="https://mintaku-blog.net/introduction-tdd/image4-5/" data-orig-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image4-e1620548965855.png?fit=999%2C919&amp;ssl=1" data-orig-size="999,919" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="image4" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image4-e1620548965855.png?fit=300%2C276&amp;ssl=1" data-large-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image4-e1620548965855.png?fit=800%2C369&amp;ssl=1" loading="lazy" src="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image4-e1620548965855.png?resize=800%2C736&#038;ssl=1" alt="" width="800" height="736" class="aligncenter wp-image-1985 size-full" srcset="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image4-e1620548965855.png?w=999&amp;ssl=1 999w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image4-e1620548965855.png?resize=300%2C276&amp;ssl=1 300w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image4-e1620548965855.png?resize=768%2C706&amp;ssl=1 768w" sizes="(max-width: 800px) 100vw, 800px" data-recalc-dims="1" /></p>
<p>シンタックス系のエラーはなくなりましたが、テスト結果が正しくありません。期待されている値は10ですが、0となっています。</p>
<p>&nbsp;</p>
<p>期待されている値が10になるように実装していきます。</p><pre class="crayon-plain-tag">public class Dollar {
  int amount = 5 * 2;

  Dollar(int amount) {
  }

  void times(int multiplier) {
  }
}</pre><p>&nbsp;</p>
<p><img data-attachment-id="1987" data-permalink="https://mintaku-blog.net/introduction-tdd/image2-8/" data-orig-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image2.png?fit=1114%2C548&amp;ssl=1" data-orig-size="1114,548" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="image2" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image2.png?fit=300%2C148&amp;ssl=1" data-large-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image2.png?fit=800%2C394&amp;ssl=1" loading="lazy" src="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image2.png?resize=800%2C394&#038;ssl=1" alt="" width="800" height="394" class="aligncenter size-large wp-image-1987" srcset="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image2.png?resize=1024%2C504&amp;ssl=1 1024w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image2.png?resize=300%2C148&amp;ssl=1 300w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image2.png?resize=768%2C378&amp;ssl=1 768w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image2.png?w=1114&amp;ssl=1 1114w" sizes="(max-width: 800px) 100vw, 800px" data-recalc-dims="1" /></p>
<p>テストが通りました。ここまでがTDDサイクルで言う「グリーン」であるという認識です。</p>
<p>&nbsp;</p>
<h2>リファクタリングする</h2>
<p>テストが成功したといえど、amountの初期値を10にしているため引数の値が変わればテストが失敗します。そのため、どんな値でも対応できるようにリファクタリングをしていきます。</p><pre class="crayon-plain-tag">public class Dollar {
  int amount;

  Dollar(int amount) {
    this.amount = amount;
  }

  void times(int multiplier) {
    amount *= multiplier;
  }
}</pre><p>&nbsp;</p>
<p><img data-attachment-id="1986" data-permalink="https://mintaku-blog.net/introduction-tdd/image3-6/" data-orig-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image3.png?fit=1104%2C512&amp;ssl=1" data-orig-size="1104,512" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="image3" data-image-description="" data-image-caption="" data-medium-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image3.png?fit=300%2C139&amp;ssl=1" data-large-file="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image3.png?fit=800%2C371&amp;ssl=1" loading="lazy" src="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image3.png?resize=800%2C371&#038;ssl=1" alt="" width="800" height="371" class="aligncenter size-large wp-image-1986" srcset="https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image3.png?resize=1024%2C475&amp;ssl=1 1024w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image3.png?resize=300%2C139&amp;ssl=1 300w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image3.png?resize=768%2C356&amp;ssl=1 768w, https://i0.wp.com/mintaku-blog.net/mintaku/wp-content/uploads/2021/05/image3.png?w=1104&amp;ssl=1 1104w" sizes="(max-width: 800px) 100vw, 800px" data-recalc-dims="1" /></p>
<p>リファクタリングをしたら再度テストを実行し、テストが成功することを確認します。</p>The post <a href="https://mintaku-blog.net/introduction-tdd/">テスト駆動開発入門を読んでTDDサイクルを試してみる</a> first appeared on <a href="https://mintaku-blog.net">みんたく</a>.]]></content:encoded>
					
					<wfw:commentRss>https://mintaku-blog.net/introduction-tdd/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1983</post-id>	</item>
	</channel>
</rss>
