たくろぐ!

29歳プログラマーの思うことと備忘録

【Qiita】伊藤淳一さんのRspecのエントリをまとめてみた

伊藤淳一さんとは

Rubyistには馴染みの深いRspecだけど、そのRspecの第一人者であるのが伊藤淳一さんだ。
日本生まれのRubyだがそのテスティングフレームワークであるRspecの専門書を日本語で書いている人である(翻訳)。
Rspecの本を一度でも探したことがあるならどれほど有名な人かはわかるのだが、とにかく彼の書いた「Everyday Rails - RSpecによるRailsテスト入門」が人気でこれだけでも彼の残した功績は大きい(らしい)。

Rspecとは

Rspecというのは、Rubyの開発現場でよく使われるテスティングフレームワークだ。
テスティングフレームワークというのは、テストをするためのフレームワークと言う意味で、テストと言ってもここでは単体テスト(Unit Test(UT))のことを指している。
単体テストとは、誤解を恐れず言えばモジュール(つまり1機能を有したファイル群のこと)単位でソースコードのロジックが要件通りに動くかどうかを確認するテストのことだが、これを自動化させられるのがRspecというわけだ。
ちなみに同じ単体テスト用のフレームワークとして、Minitestというのがある。
これは現在Rubyの標準で付属されているフレームワークで、記述もRspecのようにDSLドメイン固有言語)でなくRubyで書かれている。
つまりRubyが書ければテストも同時に書くことができるという意味で学習コストが低い。

qiita.com

さらにRspecの特徴として、ビヘイビア駆動開発(behavior driven development(BDD))というものが挙げられる。
ざっくり言えば、メソッドなどの振る舞い(=Behaviour)に焦点を当ててテストをする方法だ。
RspecはこのBDDに特化したテスティングフレームワークなのである。

テスト全般に関しては以下のQiitaのエントリがわかりやすい。

qiita.com

ちなみにRspec単体テスト用のテストツールということだが、結合テスト以降ももちろんテストのフレームワークはある。
結合テストはエンドツーエンド(End-to-End)テストとも言われ、こっちの末端からあっちの末端までというモジュール間を繋いだ、実際の動作に近いテストのことだ。
Rubyではひと昔前はCucumberというフレームワークだったようだが、現在はTurnipというものが主流らしい。
ちなみにブラウザテスト(統合テストに近いかな)ではSeleniumというフレームワークが有名だ。

結構古いがこれわかりやすい[中級者向け]

エンドツーエンドテストの自動化は Cucumber から Turnip へ

プログラミング初心者を悩ますテストの違い[初心者向け]

[Testing] システムテストとエンドツーエンドテストの違い terminology qa | CODE Q&A [日本語]

itpgsepm-note.com

早速やってみる

では早速だが、Rspecを書いてみる。
特にプログラミングはそうだが、習うより慣れろだ。
実際に手を動かしてみて初めてわかることがプログラミングにはある。

初期のRspec

describe 'テストする対象(例:Stack)' do
  context 'テストの状況(例:新しく生成したとき)' do
    #テストを実行する前処理
    before do
      @stack = Stack.new
    end
 
    it 'テストの説明(例:スタックが空であること)' do
      #期待する出力との照合
      @stack.should be_empty
    end
  end
end

参照元Ruby Association: テスト

www.ruby.or.jp

書いてわかること

テストを書くメリットは以下の通りだ。

用語的な何か

  • example
    テストの最小単位のこと

  • describe
    テスト対象を指す。
    複数のテストをまとめて、その中で対象を分けるときはネストする。

  • context
    条件を指定するときなどに使う、ON/OFFやTrue/falseのときなど分岐に使う。
    describeのエイリアス
    describeが対象を指すなら、contextは状況を指す。

  • before
    そのテストをする前の処理として記述する。

  • after
    beforeの逆。後に何かの処理をさせるときに記述する。

  • it
    実際のテストを記載するときに使う。
    マッチャなどと一緒に使うことが多い。

  • should
    逆はshould_not

  • expect_to

  • subject
    レシーバを指定するときに使う。

  • its

  • shared_examples

  • let
    ブロックの評価を引数のSymbolとして利用できる。

  • double
    スタブを作るときに使用する

  • stub
    doubleで作成したスタブにメソッドを追加できる。 もちろんオブジェクトやクラスにも使える。

  • say
    モック作成のときに使う。

  • (should_)receive
    sayでメソッドが呼ばれたら、ここで定義した値を返す。

途中です

Google Spread Sheets APIを使ってみた

やったこと

以下のエントリを実施
qiita.com

コード

HTTPリクエス

POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-length: 277
content-type: application/x-www-form-urlencoded
user-agent: google-oauth-playground
code=4%2FAAAk2BZVFWVhb6d7kIedohk5bZVx4E9shmB5ogT66cRkBotLU_2rsGQ_vB3mdowj53vfwVT8e79QGIVqFj8wdCQ&redirect_uri=https%3A%2F%2Fdevelopers.google.com%2Foauthplayground&client_id=407408718192.apps.googleusercontent.com&client_secret=************&scope=&grant_type=authorization_code

HTTPレスポンス

HTTP/1.1 200 OK
Content-length: 266
X-xss-protection: 1; mode=block
X-content-type-options: nosniff
Transfer-encoding: chunked
Expires: Mon, 01 Jan 1990 00:00:00 GMT
Vary: Origin, X-Origin
Server: GSE
-content-encoding: gzip
Pragma: no-cache
Cache-control: no-cache, no-store, max-age=0, must-revalidate
Date: Sat, 16 Jun 2018 04:28:05 GMT
X-frame-options: SAMEORIGIN
Alt-svc: quic=":443"; ma=2592000; v="43,42,41,39,35"
Content-type: application/json; charset=UTF-8
{
  "access_token": "ya29.GlvcBSID_YzBKiDlHpZn-9jg3r-BBUJvYG5HNhYGn3PrOmZWvqHZijkTxde8wTtptBnLHC7Xe1Aoo4aCjMMF8HUQ8SrvVm55NtEFeX22yph598KqXOuSncLCVHaa", 
  "token_type": "Bearer", 
  "expires_in": 3600, 
  "refresh_token": "1/xEpcXZMr0sknkgSXeD6u6FzMAHaAnZPK2Z2rgKtj9qY"
}

HTTPリクエス

POST /v4/spreadsheets HTTP/1.1
Host: sheets.googleapis.com
Content-length: 0
Content-type: application/json
Authorization: Bearer ya29.GlvcBSID_YzBKiDlHpZn-9jg3r-BBUJvYG5HNhYGn3PrOmZWvqHZijkTxde8wTtptBnLHC7Xe1Aoo4aCjMMF8HUQ8SrvVm55NtEFeX22yph598KqXOuSncLCVHaa

HTTPレスポンス

HTTP/1.1 200 OK
Content-length: 1152
X-xss-protection: 1; mode=block
Transfer-encoding: chunked
Vary: Origin, X-Origin, Referer
Server: ESF
-content-encoding: gzip
Cache-control: private
Date: Sat, 16 Jun 2018 05:05:03 GMT
X-frame-options: SAMEORIGIN
Alt-svc: quic=":443"; ma=2592000; v="43,42,41,39,35"
Content-type: application/json; charset=UTF-8
{
  "spreadsheetId": "1VfmCpGFTGpSFoY8grUXGXiqb2J1TgSCBFpOO0yjJbss", 
  "properties": {
    "locale": "ja_JP", 
    "timeZone": "Etc/GMT", 
    "autoRecalc": "ON_CHANGE", 
    "defaultFormat": {
      "padding": {
        "top": 2, 
        "right": 3, 
        "left": 3, 
        "bottom": 2
      }, 
      "textFormat": {
        "foregroundColor": {}, 
        "bold": false, 
        "strikethrough": false, 
        "fontFamily": "arial,sans,sans-serif", 
        "fontSize": 10, 
        "italic": false, 
        "underline": false
      }, 
      "verticalAlignment": "BOTTOM", 
      "backgroundColor": {
        "blue": 1, 
        "green": 1, 
        "red": 1
      }, 
      "wrapStrategy": "OVERFLOW_CELL"
    }, 
    "title": "\u7121\u984c\u306e\u30b9\u30d7\u30ec\u30c3\u30c9\u30b7\u30fc\u30c8"
  }, 
  "sheets": [
    {
      "properties": {
        "sheetType": "GRID", 
        "index": 0, 
        "sheetId": 0, 
        "gridProperties": {
          "columnCount": 26, 
          "rowCount": 1000
        }, 
        "title": "\u30b7\u30fc\u30c81"
      }
    }
  ], 
  "spreadsheetUrl": "https://docs.google.com/a/hidev.solutions/spreadsheets/d/1VfmCpGFTGpSFoY8grUXGXiqb2J1TgSCBFpOO0yjJbss/edit"
}

ここ貼り忘れた

HTTPリクエス

POST /v4/spreadsheets/1VfmCpGFTGpSFoY8grUXGXiqb2J1TgSCBFpOO0yjJbss:batchUpdate HTTP/1.1
Host: sheets.googleapis.com
Content-length: 2892
Content-type: application/json
Authorization: Bearer ya29.GlvcBSID_YzBKiDlHpZn-9jg3r-BBUJvYG5HNhYGn3PrOmZWvqHZijkTxde8wTtptBnLHC7Xe1Aoo4aCjMMF8HUQ8SrvVm55NtEFeX22yph598KqXOuSncLCVHaa
{
  "requests": [
    {
      "addChart": {
        "chart": {
          "spec": {
            "title": "å½èªãç®æ°ãçç§",
            "basicChart": {
              "chartType": "COLUMN",
              "legendPosition": "RIGHT_LEGEND",
              "axis": [
                {
                  "position": "BOTTOM_AXIS"
                },
                {
                  "position": "LEFT_AXIS"
                }
              ],
              "domains": [
                {
                  "domain": {
                    "sourceRange": {
                      "sources": [
                        {
                          "startRowIndex": 0,
                          "endRowIndex": 4,
                          "startColumnIndex": 0,
                          "endColumnIndex": 1
                        }
                      ]
                    }
                  }
                }
              ],
              "series": [
                {
                  "series": {
                    "sourceRange": {
                      "sources": [
                        {
                          "startRowIndex": 0,
                          "endRowIndex": 4,
                          "startColumnIndex": 1,
                          "endColumnIndex": 2
                        }
                      ]
                    }
                  },
                  "targetAxis": "LEFT_AXIS"
                },
                {
                  "series": {
                    "sourceRange": {
                      "sources": [
                        {
                          "startRowIndex": 0,
                          "endRowIndex": 4,
                          "startColumnIndex": 2,
                          "endColumnIndex": 3
                        }
                      ]
                    }
                  },
                  "targetAxis": "LEFT_AXIS"
                },
                {
                  "series": {
                    "sourceRange": {
                      "sources": [
                        {
                          "startRowIndex": 0,
                          "endRowIndex": 4,
                          "startColumnIndex": 3,
                          "endColumnIndex": 4
                        }
                      ]
                    }
                  },
                  "targetAxis": "LEFT_AXIS"
                }
              ],
              "headerCount": 1
            },
            "hiddenDimensionStrategy": "SKIP_HIDDEN_ROWS_AND_COLUMNS"
          },
          "position": {
            "overlayPosition": {
              "anchorCell": {
                "columnIndex": 5
              },
              "offsetXPixels": 34,
              "offsetYPixels": 15,
              "widthPixels": 470,
              "heightPixels": 290
            }
          }
        }
      }
    }
  ]
}

HTTPレスポンス

HTTP/1.1 200 OK
Content-length: 1376
X-xss-protection: 1; mode=block
Transfer-encoding: chunked
Vary: Origin, X-Origin, Referer
Server: ESF
-content-encoding: gzip
Cache-control: private
Date: Sat, 16 Jun 2018 05:25:45 GMT
X-frame-options: SAMEORIGIN
Alt-svc: quic=":443"; ma=2592000; v="43,42,41,39,35"
Content-type: application/json; charset=UTF-8
{
  "spreadsheetId": "1VfmCpGFTGpSFoY8grUXGXiqb2J1TgSCBFpOO0yjJbss", 
  "replies": [
    {
      "addChart": {
        "chart": {
          "chartId": 1861209020, 
          "position": {
            "overlayPosition": {
              "anchorCell": {
                "columnIndex": 5
              }, 
              "widthPixels": 470, 
              "offsetYPixels": 15, 
              "offsetXPixels": 34, 
              "heightPixels": 290
            }
          }, 
          "spec": {
            "hiddenDimensionStrategy": "SKIP_HIDDEN_ROWS_AND_COLUMNS", 
            "titleTextFormat": {
              "fontFamily": "Roboto"
            }, 
            "fontName": "Roboto", 
            "basicChart": {
              "domains": [
                {
                  "domain": {
                    "sourceRange": {
                      "sources": [
                        {
                          "endRowIndex": 4, 
                          "startRowIndex": 0, 
                          "startColumnIndex": 0, 
                          "endColumnIndex": 1
                        }
                      ]
                    }
                  }
                }
              ], 
              "chartType": "COLUMN", 
              "legendPosition": "RIGHT_LEGEND"
            }, 
            "title": "\u56fd\u8a9e\u3001\u7b97\u6570\u3001\u7406\u79d1"
          }
        }
      }
    }
  ]
}