蒼時弦也
蒼時弦也
資深軟體工程師
發表於

初始化後端專案 - Cucumber 的文件測試法

這篇文章是 Cucumber 的文件測試法 系列的一部分。

前端的實作目前告一段落,我們將關注放到後端的部分。這次會直接使用 Grape 這個 Gem 來直接搭建 API 伺服器而不使用 Rails,並且刻意使用 Cucumber 來撰寫測試,在正常的狀況下只需要使用跟前端同一份即可,這次主要是展示針對後端可以怎樣實現。

初始化

我們可以用 bundle init 建立一個空的 Ruby 的專案,並且安裝所需的 Gem 來搭建環境。

修改 Gemfile 加入我們需要使用到的套件。

 1# frozen_string_literal: true
 2
 3source 'https://rubygems.org'
 4
 5gem 'grape'
 6gem 'puma'
 7gem 'rack'
 8
 9group :development do
10  gem 'rubocop'
11end
12
13group :test do
14  gem 'cucumber'
15  gem 'rack-test'
16  gem 'rspec'
17end

運行 bundle install 安裝完畢後,我們再運行 bundle exec cucumber --init 將測試環境搭出來,並且加入一些用於測試的環境設定到 features/support/env.rb 裡面。

 1ENV['RACK_ENV'] = 'test'
 2
 3require_relative '../../app'
 4require 'rack/test'
 5
 6def app
 7  Shop::API
 8end
 9
10World(Rack::Test::Methods)

這邊我們用 require_relative 去載入我們預定的主程式 app.rb 並且針對 rack-test 這個測試工具,定義一個在運行會用到的 app 方法,將 Shop::API 這個透過 Grape 來實現的 Rack 介面傳入,這樣我們就能在測試正常呼叫我們搭建的 API 伺服器。

撰寫測試

跟前端一樣,我們會先撰寫一個初始的測試來確認環境設定正確,加入 features/root.feature 來確認可以正常的取的一個 JSON API 回應。

1#language:zh-TW
2功能: Root
3  場景: 服務正常
4 我開啟 "/"
5    那麼 我會看到 JSON 屬性 "ok" 為真

這兩個步驟是還沒有被定義的,那麼繼續在 features/step_definitions/common.rb 裡面描述對應的行為。

 1When('我開啟 {string}') do |path|
 2  get path
 3end
 4
 5Then('我會看到 JSON 屬性 {string} 為真') do |json_path|
 6  json = JSON.parse(last_response.body)
 7  path = json_path.split('.')
 8
 9  expect(json.dig(*path)).to be_truthy
10end

在這邊用了一個小技巧來檢查 JSON 的資料,因為我們經常會有巢狀的 JSON 內容,那麼可以利用 Ruby 的 #dig 方法來取得某個值,舉例來說。

1{
2  "name": "Aotoki",
3  "job": {
4    "title": "Senior Software Engineer",
5    "department": "Cloud Team"
6  }
7}

想要拿到 job 裡面的 title 可以用 json.dig('job', 'title') 這樣做,但是在 Cucumber 裡面都是純文字內容,因此可以用 job.title 的格式來描述,我們只需要在步驟定義上用 #split('.') 拆開即可。

實作功能

最後,我們要加上 app.rb 以及給 Rack 使用的 config.ru 讓我們可以實際的運行這個伺服器。

首先,在 config.ru 加入以下內容。

1# frozen_string_literal: true
2
3require_relative 'app'
4
5run Shop::API

這樣待會就可以用 bundle exec rackup 自動以 Puma 當伺服器啟動我們的後端 API 伺服器。

然後繼續加入 app.rb 定義一個全新的 API 並且回應我們預期的內容。

 1# frozen_string_literal: true
 2
 3require 'bundler/setup'
 4Bundler.require(:default, ENV['RACK_ENV'].to_sym)
 5
 6module Shop
 7  # :nodoc:
 8  class API < Grape::API
 9    format :json
10
11    get do
12      { ok: true }
13    end
14  end
15end

完成一個最基礎的 API 實作後,我們就可以運行 bundle exec cucumber 來驗證結果,如果一切順利,就可以看到通過測試的訊息,我們就可以繼續後續跟前端整合的實作。