---
# System prepended metadata

title: 2020年10月10日モブプロ#8

---

# 2020年10月10日モブプロ#8

[MDの書き方](https://qiita.com/tbpgr/items/989c6badefff69377da7)

モブプロのコンテンツは🤟がついています。

# 本日の目標
ひたすらテストコードを書いていく！

# Jestの参考サイト

- [Facebook製のJavaScriptテストツール「Jest」の逆引き使用例 - Qiita](https://qiita.com/chimame/items/e97883fd46b67529d59f)
- [Getting Started - Jest](https://jestjs.io/docs/ja/getting-started)

# テストコードを書いていこう🤟
- エンドポイントのテストはJestはできないので以下を使用する
    - https://www.npmjs.com/package/supertest

## テストの分類分け

describeを使って、ファイル単位、メソッド単位にテストを分けて書いていく
```javascript=
describe('routers/tasks.js', () => {
  describe('get method', () => {
  })
})
```

## GETメソッドのテストコードを書く

### Task全取得

```javascript=
describe('get method', () => {
  it('response', async () => {
    const response = await request(app).get('/tasks')
    expect(response.statusCode).toBe(200)
  })
})
```

いい感じ。
```shell=
> jest
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.415 s
```

でも、なにかエラーが表示される。
```shell=
●  Cannot log after tests are done. Did you forget to wait for something async in your test?
    Attempted to log "Executing (default): ALTER TABLE `Tasks` CHANGE `title` `title` VARCHAR(255) NOT NULL;".

      at CustomConsole.log (node_modules/@jest/console/build/CustomConsole.js:185:10)
      at Sequelize.log (node_modules/sequelize/lib/sequelize.js:1171:15)
      at Query._logQuery (node_modules/sequelize/lib/dialects/abstract/query.js:352:22)
      at Query.run (node_modules/sequelize/lib/dialects/mysql/query.js:36:27)
      at node_modules/sequelize/lib/sequelize.js:619:28
      at Function.sync (node_modules/sequelize/lib/model.js:1349:11)
```

APIサーバ起動時にコンソールログが出力されるが、そのログに対してテストしなくて大丈夫かどうかを尋ねるメッセージの模様。
本来は、ちゃんとテストするか、出力されないようにするなどの対応をするべきだが、一旦以下のオプションで無視する。

```shell=
jest --silent
```

### レスポンスが配列かどうかのテスト

```javascript=
expect(Array.isArray(response.body)).toBe(true) // => passed!
```

上記を先程の`expect()`の下に追加。

`tobe(true)`は`toBeTruthy()`に置き換えることができる。

```javascript=
expect(Array.isArray(response.body)).toBeTruthy() // => passed!
```

### ID指定での取得テスト

```javascript=
it('response with id', async () =>{
  const response = await request(app).get('/tasks/13')
  expect(response.statusCode).toBe(200)
  // IDはNumber型？
  expect(Number.isInteger(response.body.id)).toBeTruthy()
  // titleは合ってる？
  expect(response.body.title).toBe('test1')
  // doneはfalseかな？
  expect(response.body.done).toBeFalsy()
})
```

### 存在しないIDのエラーテスト

```javascript=
// id = 12は存在しないはず...

it('response with unknown id', async () =>{
  const response = await request(app).get('/tasks/12')
  expect(response.statusCode).toBe(404)
})
```

## テストデータの追加

上記の書き方と汎用性がないのでテストデータを追加する。

```javascript=
const Task = require('../src/models/tasks')

// テストデータを新規追加
const task = await Task.create({title:'test'})
const id = task.id
```

## POSTメソッドのテストコードを書いていく

```javascript=
describe('post method', () => {
  it('response with data', async () => {
    const data = {title: "test"}
    const response = await request(app).post('/tasks').send(data)
    expect(response.statusCode).toBe(201)
  })
})
```

### 失敗するようにしてみる

```javascript=
it('response without data', async () => {
  const response = await request(app).post('/tasks')
  expect(response.statusCode).toBe(400)
})
```

エラーで落ちちゃう。

エラー処理を書いてなかった！

```javascript=
// routers/tasks.js

router.post('/tasks', async (req, res) => {
    const title = req.body.title

    try {
      const task = await Task.create({
        title
      })

      res.status(201).send(task)
    } catch(e) {
      res.status(400).send()
    }
})
```

エラー処理を追加してあげる。

## DELETEメソッドのテストコードを書いていく

```javascript=
describe('delete method', () => {
    it('response with id', async () => {
      const task = await Task.create({title:'test'})
      const id = task.id

      const response = await request(app).delete(`/tasks/${id}`)
      // 削除完了している？
      expect(response.statusCode).toBe(200)
      // 中身消えてる？
      expect(response.body.id).toBeUndefined()
    })

    // 存在しないIDで404が返ってくるか
    it('response with unknown id', async () => {
      const id = 0
      const response = await request(app).delete(`/tasks/${id}`)
      expect(response.statusCode).toBe(404)
    })
})
```

## PATCHメソッドのテストコードを書いていく

```javascript=
describe('patch method', () => {
    it('response with id and data', async () => {
      const task = await Task.create({title:'test'})
      const id = task.id
      const data = { title:"test2",done:true}

      const response = await request(app).patch(`/tasks/${id}`).send(data)
      // 成功した？
      expect(response.statusCode).toBe(200)
      expect(response.body.id).toBe(id)
      expect(response.body.done).toBeTruthy()
      expect(response.body.title).toBe(data.title)
    })
})
```

### IDがなかった場合の処理

```javascript=
it('respose with unknown id', async ()=> {
  const id = 0
  const data = { title:"test2",done:true}

  const response = await request(app).patch(`/tasks/${id}`).send(data)
  expect(response.statusCode).toBe(404)    
})
```

## テストコード記述時の注意💥

### **テストコードは共通化しない！**

どこで失敗したかわからなくなるため共通化はご法度。

コピペで記述しましょう。