測試驅動開發 Ruby 命令行工具實戰

TL;DR; 本文介紹了 to_yaml 的開發過程當中如何採用 TDD 方法開發功能,以及用到的免費服務 GitHub / TravisCI / RubyGemsgit

TDD (測試驅動開發)是敏捷開發中的一項核心實踐和技術,也是一種設計方法論。 TDD 的原理是在開發功能代碼以前,先編寫單元測試用例代碼,測試代碼肯定須要編寫什麼產品代碼。github

to_yaml 是一款命令行工具,JSON 輸入轉爲 YAML 文本輸出json

<!--excerpt-->ruby

背景

先從最近使用的 ElasticSearch 提及。 做爲通用的日誌收集、分析與展現的工具集,ELK 工具棧已經至關普及。 其中在管理 ElasticSearch 集羣時,大部分時間都要使用 HTTP 接口跟 JSON 格式數據打交道。app

ES 輸出 JSON 數據內容比較多,即便使用 ?pretty 參數,仍然難看清數據的層次關係。 ?pretty 的一個反作用是輸出內容過長,浪費了大量的屏幕縱向空間。框架

使用 YAML 格式可以在很大程度上緩解空間的問題。 基於這個想法,作了一個簡單的工具出來,發佈在了 RubyGems.orgcurl

初步想法

在實際使用 JSON 時,但願的是能直接將接口輸出內容直接轉換爲 YAML 格式。 如這樣的形式:svg

$ curl -s -XGET http://localhost:9200/_mappings | to_yaml

另外,要把這個工具做爲軟件包發佈出來,方便別的地方使用。 ruby 程序的第一選擇便是 gem工具

使用 gem 發佈還有一個好處:能夠利用 ruby 的開發工具,如 bundlerspec 等,來發布質量可控的軟件。單元測試

開始動手

建立 gem 框架目錄

現階段最簡單的工具是 bundle gem

$ bundle gem to_yaml
Creating gem 'to_yaml'...
Code of conduct enabled in config
MIT License enabled in config
      create  to_yaml/Gemfile
      create  to_yaml/.gitignore
      create  to_yaml/lib/to_yaml.rb
      create  to_yaml/lib/to_yaml/version.rb
      create  to_yaml/to_yaml.gemspec
      create  to_yaml/Rakefile
      create  to_yaml/README.md
      create  to_yaml/bin/console
      create  to_yaml/bin/setup
      create  to_yaml/CODE_OF_CONDUCT.md
      create  to_yaml/LICENSE.txt
      create  to_yaml/.travis.yml
      create  to_yaml/.rspec
      create  to_yaml/spec/spec_helper.rb
      create  to_yaml/spec/to_yaml_spec.rb
Initializing git repo in /private/tmp/to_yaml

更改 to_yaml.gemspec 中的基本信息,全部標記 TODO 的全酌情修改。

github 上建立一個代碼庫。而後 git add . && git commit -am Init && git push

如今咱們已經有了基本的框架。

代碼未動,測試先行

查看 Rakefile 內容以下

require "bundler/gem_tasks"
require "rspec/core/rake_task"

RSpec::Core::RakeTask.new(:spec)

task :default => :spec

命令行執行 rake specrake,能夠執行默認的測試用例。

來讓咱們爲 to_yaml 工具寫一個最簡單的用例。

打開 spec/to_yaml_spec.rb 文件,在 describe ToYaml 與對應 end 直接增長一個用例

it 'parse json with cli' do
    json_str = '{"a": [1, 2, 3], "b": {"c": "d"}}'
    yaml_str = '---\na:\n- 1\n- 2\n- 3\nb:\n  c: d\n'

    cli_output = run_cli('./exe/to_yaml', json_str)
    expect(cli_output).to eq(yaml_str)
  end

修改 spec/spec_helper.rb,加入 helper 方法

require 'open3'

def run_cli(exe="./exe/to_yaml", input)
  cmd = %Q{echo \'#{input}\'| bundle exec #{exe}}
  output = Open3.popen3(cmd) { |stdin, stdout, stderr, wait_thr| stdout.read }
end

注意這裏面,咱們構造一個 JSON 字符串 json_str,和一個 YAML 字符串 yaml_str。 指望的行爲是運行 ./exe/to_yaml 命令處理 json_str 後,輸出 cli_outputyaml_str 一致。

如今執行這個測試 rake specrake,毫無懸念失敗了。

不過這是一個好的開頭,咱們有了明確的目標:讓測試成功。

建立命令行

to_yaml.gemspec 中,經過 spec.executables 指定了可執行文件的路徑爲 ./exe/ 目錄。

spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }

to_yaml 命令文件就放在這裏。

如今建立 exe/to_yaml 文件,加入內容:

#!/usr/bin/env ruby

require 'json'
require 'yaml'

puts JSON.load(STDIN).to_yaml

再簡單不過的一個單行腳本。 按咱們的設想,從 STDIN 讀入內容,轉化爲 YAML 格式。 本着 [YAGNI](https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it) 原則,沒作任何額外的容錯 - -!

如今執行測試

$ rake spec

ToYaml
  has a version number
  parse json with cli

Finished in 0.77046 seconds (files took 0.09961 seconds to load)
2 examples, 0 failures

太棒了,測試用例所有成功。

測試,AGAIN

目前爲止的測試還在靠手工驅動執行。 而在實踐中,則須要將持續構建整合進開發流程,全部狀態都能夠追溯,並能及時反饋構建結果

gem 目錄下,咱們能夠找到一個 .travis.yml 文件。 travis-ci 是開源世界應用最廣泛的持續集成工具。

使用 travis-ci 須要先作設置。 到 https://travis-ci.org,使用 github 賬號登陸,並從 github 中添加咱們的 to_yaml 項目。

設置完畢,下次咱們 push 代碼到 githubtravis-ci 能夠自動開始構建。 爲了方便從 GitHub 頁面看到項目 Build 狀態,在 README.md 文件裏增長項目的狀態圖標

[![Build Status](https://travis-ci.org/Lax/to_yaml.svg?branch=master)](https://travis-ci.org/Lax/to_yaml)

剛纔已經在本地測試成功,如今將代碼 commit 並 push 到 github。 從 travis-ci 頁面,咱們看到已經建立了第一次構建 Build #1。 很幸運,此次構建到結果也成功了!

發佈

rake release 能夠自動建立一個發佈 tag,將代碼 push 到 github。 並 build 出 to_yaml.gem,經過 gem push 發佈到 rubygems.org。

使用

下次使用時,直接 gem install to_yaml,既能夠在 PATH 中搜索到 to_yaml 執行程序。

測試一個公開的 JSON 服務:

$ curl -s http://jsonip.com
{"ip":"123.45.67.89","about":"/about","Pro!":"http://getjsonip.com"}

$ curl -s http://jsonip.com | to_yaml
---
ip: 123.45.67.89
about: /about
Pro!: http://getjsonip.com

很清爽,有木有!

總結展望

本文介紹的是一個極簡工具的開發過程,但願你能感覺到測試驅動開發所發揮的做用。

做者在實際項目中也儘量實踐 TDD 方法,發佈的工具如 aliyun.gem (一個阿里雲API的客戶端) 也採用了相似流程。 甚至本博客也引入了 travis-ci 作持續構建和測試,確保內容中引用的圖片和連接無死鏈。

若是你對本文描述的內容感興趣,歡迎發佈評論來交流。

相關文章
相關標籤/搜索