TL;DR; 本文介绍了 to_yaml 的开发过程中如何采用 TDD 方法开发功能,以及用到的免费服务 GitHub / TravisCI / RubyGems 。
TDD (测试驱动开发)是敏捷开发中的一项核心实践和技术,也是一种设计方法论。 TDD 的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码。
to_yaml 是一款命令行工具, 将 JSON 输入转为 YAML 文本输出 。
背景
先从最近使用的 ElasticSearch 说起。 作为通用的日志收集、分析与展示的工具集, ELK 工具栈已经相当普及。 其中在管理 ElasticSearch 集群时,大部分时间都要使用 HTTP 接口跟 JSON 格式数据打交道。
ES 输出 JSON 数据内容比较多,即使使用 ?pretty 参数,仍然难看清数据的层次关系。 ?pretty 的一个副作用是输出内容过长,浪费了大量的屏幕纵向空间。
使用 YAML 格式能够在很大程度上缓解空间的问题。 基于这个想法,做了一个简单的工具出来,发布在了RubyGems.org 。
初步想法
在实际使用 JSON 时,希望的是能直接将接口输出内容直接转换为 YAML 格式。 如这样的形式:
$ curl -s -XGET http://localhost:9200/_mappings | to_yaml
另外,要把这个工具作为 软件包 发布出来,方便别的地方使用。 ruby 程序的第一选择即是 gem 。
使用 gem 发布还有一个好处:可以利用 ruby 的开发工具,如 bundle 、 rspec 等,来发布质量可控的软件。
开始动手
创建 gem 框架目录
现阶段最简单的工具是 bundle gem 。
$ bundle gem to_yamlCreating 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.rbInitializing 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 spec 或 rake ,可以执行默认的测试用例。
来让我们为 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_output 与 yaml_str 一致。
现在执行这个测试 rake spec 或 rake ,毫无悬念失败了。
不过这是一个好的开头,我们有了明确的目标:让测试成功。
创建命令行
在 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 rubyrequire 'json'require 'yaml'puts JSON.load(STDIN).to_yaml
再简单不过的一个单行脚本。 按我们的设想,从 STDIN 读入内容,转化为 YAML 格式。 本着 [YAGNI](https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it) 原则,没做任何额外的容错 - -!
现在执行测试
$ rake specToYaml has a version number parse json with cliFinished in 0.77046 seconds (files took 0.09961 seconds to load) examples, 0 failures
太棒了,测试用例全部成功。
测试, AGAIN
目前为止的测试还在靠手工驱动执行。 而在实践中,则需要 将持续构建整合进开发流程 ,所有状态都 可以追溯 ,并能 及时反馈构建结果 。
在 gem 目录下,我们可以找到一个 .travis.yml 文件。 travis-ci 是开源世界应用最普遍的持续集成工具。
使用 travis-ci 需要先做设置。 到 https://travis-ci.org,使用 github 帐号登录,并从 github 中添加我们的 to_yaml 项目。
设置完毕,下次我们 push 代码到 github , travis-ci 可以自动开始构建。 为了方便从 GitHub 页面看到项目 Build 状态,在 README.md 文件里增加项目的状态图标
[](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.89about: /aboutPro!: http://getjsonip.com很清爽,有木有!
总结展望
本文介绍的是一个极简工具的开发过程,希望你能感受到测试驱动开发所发挥的作用。
作者在实际项目中也尽可能实践 TDD 方法,发布的工具如 aliyun.gem (一个阿里云API的客户端) 也采用了类似流程。 甚至 本博客 也引入了 travis-ci 做持续构建和测试,确保内容中引用的图片和链接无死链。
如果你对本文描述的内容感兴趣,欢迎发布评论来交流。
原文链接:http://outofmemory.cn/ruby/Test-driven-development-with-ruby
共同學習,寫下你的評論
評論加載中...
作者其他優質文章