Jenkins入門【2.0対応】 - オープンソースCIツール(2)
Jenkinsでテストを実行してみよう+Rubyテストの基礎(RSpec&Turnip使用)
Jenkinsを使って小さなテストを自動実行して、開発スピードを飛躍的に向上させよう。また、MacでのRuby/Rails環境の構築方法から、テストフレームワーク「RSpec」とインテグレーションテスト環境「Turnip」を使ったテストの書き方までを解説する。
前回の記事を読んでJenkinsの環境を構築することはできただろうか? 今回は簡単なサンプルアプリケーションの作成を行ってみようと思う。同時に、Rubyの標準的なテストフレームワークのRSpecと、インテグレーションテスト環境であるTurnipを使ったテストの書き方を解説する。作成したテストを、Jenkinsを使って自動実行できるようになれば、あなたの開発スピードは飛躍的に向上することだろう。
Railsの開発環境を構築しよう
2013年10月にリリースされたMac OS X 10.9(通称Mavericks)は、Rubyプログラマーにとって素晴らしい開発環境を提供してくれた。なんと標準の状態で2.0系の新しいRubyが利用できるのだ。追加インストール無しで最新のRubyを触れるのは非常に魅力的だが、今後のRubyのリリースを考えて「RVM」や「rbenv」というRuby実行環境を管理してくれるツールをインストールしておこう(※以下のインストール例は、執筆時点で最新バージョンのOS X El Capitanで行ったものである)*1。
RVM(Ruby Version Manager)とrbenvは、Rails(Ruby on Rails)開発で広く使われている実行環境管理ツールだ。機能はほぼ同じなので周りにRubyプログラマーがいれば、その人が使用している方に合わせるのがよいだろう。ここではrbenvを利用して開発環境を構築してみようと思う。なお、Ruby環境をすでに構築済みの場合は、「アプリケーションの作成とテスト」の章まで読み飛ばしてよい。
- *1 編集部註: 本稿ではMacを使っているが、Ruby環境さえインストールしてしまえば、「アプリケーションの作成とテスト」はLinuxやWindowsでも同じ手順で本稿の内容を試せる(※本稿ではLinux/Windows環境へのRuby&Rails環境のインストール方法の説明は割愛する)。ちなみにWindowsについては、今夏リリース予定のWindows 10 Anniversary UpdateでBashが使えるようになるので状況が変わってくる可能性があるが、現時点ではインストーラーを使ってRuby環境を構築するのが一般的である。一方、本稿の「Jenkinsでのテスト実行」は、rbenvをインストールしておくことが前提となっているので注意してほしい(※つまりWindows向けのインストーラーを使った場合は試せない)。
rbenvのインストール
rbenvは、前回も利用したHomebrewを使って簡単にインストールできる。
$ brew update
$ brew install rbenv ruby-build
|
ruby-buildをインストール済みで最新化したい場合は、brew install
の部分をbrew upgrade
に変えて実行すればよい。
ターミナルに上記のコマンドを入力してしばらく待つとインストールが完了し、次のように表示される。
$ brew install rbenv ruby-build
==> Installing dependencies for rbenv: openssl, ruby-build
==> Installing rbenv dependency: openssl
==> Downloading https://homebrew.bintray.com/bottles/openssl-1.0.2h_1.el_capitan
######################################################################## 100.0%
==> Pouring openssl-1.0.2h_1.el_capitan.bottle.tar.gz
==> Caveats
A CA file has been bootstrapped using certificates from the system
keychain. To add additional certificates, place .pem files in
/usr/local/etc/openssl/certs
and run
/usr/local/opt/openssl/bin/c_rehash
This formula is keg-only, which means it was not symlinked into /usr/local.
Apple has deprecated use of OpenSSL in favor of its own TLS and crypto libraries
Generally there are no consequences of this for you. If you build your
own software and it requires this formula, you'll need to add to your
build variables:
LDFLAGS: -L/usr/local/opt/openssl/lib
CPPFLAGS: -I/usr/local/opt/openssl/include
==> Summary
/usr/local/Cellar/openssl/1.0.2h_1: 1,691 files, 12M
==> Installing rbenv dependency: ruby-build
==> Downloading https://github.com/rbenv/ruby-build/archive/v20160426.tar.gz
Already downloaded: /Library/Caches/Homebrew/ruby-build-20160426.tar.gz
==> ./install.sh
/usr/local/Cellar/ruby-build/20160426: 215 files, 124.6K, built in 1 second
==> Installing rbenv
==> Downloading https://homebrew.bintray.com/bottles/rbenv-1.0.0.el_capitan.bott
######################################################################## 100.0%
==> Pouring rbenv-1.0.0.el_capitan.bottle.tar.gz
==> Caveats
Rbenv stores data under ~/.rbenv by default. If you absolutely need to
store everything under Homebrew's prefix, include this in your profile:
export RBENV_ROOT=/usr/local/var/rbenv
To enable shims and autocompletion, run this and follow the instructions:
rbenv init
==> Summary
/usr/local/Cellar/rbenv/1.0.0: 36 files, 61.9K
|
次にホームディレクトリに存在する「.bash_profile」に次の行を追加する。
PATH="$HOME/.rbenv/shims:$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
|
rbenv
コマンドを実行して、次のように表示されれば成功だ。
$ rbenv
rbenv 1.0.0
Usage: rbenv <command> [<args>]
Some useful rbenv commands are:
commands List all available rbenv commands
local Set or show the local application-specific Ruby version
global Set or show the global Ruby version
shell Set or show the shell-specific Ruby version
install Install a Ruby version using ruby-build
uninstall Uninstall a specific Ruby version
rehash Rehash rbenv shims (run this after installing executables)
version Show the current Ruby version and its origin
versions List all Ruby versions available to rbenv
which Display the full path to an executable
whence List all Ruby versions that contain the given executable
See `rbenv help <command>' for information on a specific command.
For full documentation, see: https://github.com/rbenv/rbenv#readme
|
Rubyのインストール
無事、rbenvのインストールが完了したら、rbenv経由でRubyをインストールしてみよう。今回は(執筆時点で)最新版のRuby-2.3.1をインストールしてみる。
$ rbenv install 2.3.1
|
上記のコマンドを入力してしばらく待つと、次のメッセージが表示される。
Downloading ruby-2.3.1.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.bz2
Installing ruby-2.3.1...
Installed ruby-2.3.1 to /Users/yamamotokazuhisa/.rbenv/versions/2.3.1
|
次のコマンドで、Rubyがインストールされていることを確認する。
$ rbenv versions
* system
2.3.1
|
うまくインストールされているのが確認できたら、デフォルトでruby-2.3.1を利用するように設定変更を行う(リスト5)。
$ rbenv global 2.3.1
|
アプリケーションの作成とテスト
Rubyがインストールされ、アプリケーションを開発する準備が整った。次は簡単なアプリケーションを作成してみる。
アプリケーションの作成
次のコマンドを入力し、ユーザー管理アプリケーションを作成してみよう。
1
2
3
4
5
6
|
$ gem install rails
$ rails new circle -T
$ cd circle
$ rails g scaffold user name:string age:integer
$ rake db:migrate
$ rake db:test:prepare
$ rails s
|
- 1RubyGemsからRailsをインストール。
- 2「circle」というプロジェクトをテスト無しで作成。
- 3userメンテ画面を、scaffold機能を使用して作成。
- 4DBの作成。
- 5テスト用DBの作成。
- 6アプリケーションサーバーの起動。
アプリケーションサーバーを起動した後、Webブラウザーで次のアドレスを開くと、scaffoldで作成されたWebページが表示される(図1)。
- http://localhost:3000/users
RSpecのセットアップ
テストフレームワークのRSpecをセットアップするために、scaffold機能で生成されたcircle
フォルダー直下のGemfile
ファイルを編集して「rspec-rails」というGemの設定を記述しよう。
source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.2.6'
……中略……
# Use debugger
# gem 'debugger', group: [:development, :test]
# 1
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug'
gem 'rspec-rails'
end
……後略……
|
Gemfileはcircle
プロジェクト作成時に、プロジェクトのルートディレクトリ内に生成されている(例えば「/Users/<ユーザー名>/circle/Gemfile」というパスになる)。
- 1一番下に
development
とtest
の環境を指定して、「rspec-rails」というGemを設定。
次にGemの更新を行う。
$ bundle install
|
次にRSpecのセットアップを行う。
$ rails generate rspec:install
|
プロジェクトディレクトリの下にspec
ディレクトリができたのが確認できると思う。
また設定ファイルとして.rspec
も作成されるので、そのファイル内容を次のように修正しておこう。
1
|
--color
--format documentation
|
- 1
--format documentation
を追加。
このフォーマット指定を行うことで、テスト実行時に、より詳細な情報が表示されるようになる。
アプリケーションの修正とユニットテストの作成
scaffold機能で作成したアプリケーションのUserモデルを若干改造しつつ、テストを書いてみよう。
まずUserモデルに対して次のバリデーションを追加する。
1
2
|
class User < ActiveRecord::Base
validates :name,
presence: true,
length: {maximum: 20}
validates :age,
presence: true,
numericality: {greater_than_or_equal_to: 0,
less_than_or_equal_to: 1000}
end
|
- 1必須入力および「入力値の最大文字数が20であること」。
- 2必須入力および「入力値が0~1000の範囲であること」。
次にUserモデルのテストを記述する*2。モデルを作成してからRSpecを導入したので、テストファイルはまだ存在しないため、リスト10に示すファイルは自分で作成する必要がある。
require 'rails_helper'
describe User do
context '何も入力しなかった場合' do
subject { User.create }
it { should_not be_valid}
it { expect(subject.errors[:name].size).to eq 1 }
it { expect(subject.errors[:age].size).to eq 2 }
end
context '名前が文字数をオーバーしている場合' do
subject { User.create(name: 'aaaaaaaaaabbbbbbbbbbc',age: 10) }
it { should_not be_valid }
it { expect(subject.errors[:name].size).to eq 1 }
it { expect(subject.errors[:age].size).to eq 0 }
end
context '年齢が範囲を超えている場合' do
subject { User.create(name: 'taro',age: 1001) }
it { should_not be_valid }
it { expect(subject.errors[:name].size).to eq 0 }
it { expect(subject.errors[:age].size).to eq 1 }
end
context '正常なデータがセットされた場合' do
subject { User.create(name: 'taro',age: 20) }
it { should be_valid }
end
end
|
なお、spec/models
フォルダーは自分で作成する。
- *2 実際には、本稿のサンプルで書いているような細かなレベルのテストは書かなくてよい。なぜならRailsのバリデーション機能自体をテストしているようなものだからだ。本来は、モデルに実装した独自のメソッドが正しく動作していることに注力してテストを書くべきである。
さて、ここまでできたらアプリケーションを実際に動かしてみよう。前掲の図1にある[New User]リンクをクリックすると、新規ユーザーのデータ登録用ページが表示される。ここで何も入力せず[Create User]ボタンを押すとどうなるだろうか?(図2を参照)
モデルに設定したバリデーションが正しく機能しているのが確認できる。
RSpecを実行すると、Userモデルのバリデーションのテストが実行される(リスト11)。
$ bundle exec rspec
User
何も入力しなかった場合
should not be valid
should eq 1
should eq 2
名前が文字数をオーバーしている場合
should not be valid
should eq 1
should eq 0
年齢が範囲を超えている場合
should not be valid
should eq 0
should eq 1
正常なデータがセットされた場合
should be valid
Finished in 0.04793 seconds (files took 1.87 seconds to load)
10 examples, 0 failures
|
プロジェクトのルートディレクトリでこのコマンドを実行する。
インテグレーションテストの作成
Railsでの開発においてインテグレーションテスト(=結合テスト)は、長らく「Cucumber」(キューカンバー)というフレームワークが使用されてきた。Gherkin(ガーキン)記法という非エンジニアにも読みやすい書き方でテストを記述できる半面、RSpecとは全く別の仕組みで実行しなければならず、Jenkinsで実行するにはやや手間がかかる仕組みだった。
しかし、最近はRSpecからGherkin記法で記述したテストを実行できる「Turnip」(ターニップ)というフレームワークが登場し、注目を集めている。ここではTurnipを使用して簡単なテストを書いてみようと思う。
まず、GemfileにTurnipの動作に必要なGemを追記する(リスト12)。
1
2
|
source 'https://rubygems.org'
……中略……
group :development, :test do
gem 'byebug'
gem 'rspec-rails'
gem 'capybara'
gem 'turnip'
end
……後略……
|
- 1仮想的なWebブラウザーでテストを行うために必要。
- 2Gherkin記法でRSpecを書くことができるフレームワーク。
RSpecを追加したときと同様にbundle install
を行っておこう(リスト13)。
$ bundle install
|
次にrspec
コマンドでfeatureファイル(=feature:機能、scenario:シナリオ、step:ステップというテスト手順をGherkin記法で記述したファイル)を実行できるよう、.rspec
ファイルを次のように修正する。
--require rails_helper -r turnip/rspec
--color
--format documentation
|
次に、rails_helper.rb
ファイルを次のように修正し、Turnipを実行できるようにしよう。
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'spec_helper'
require 'rspec/rails'
Dir.glob("spec/**/*steps.rb") { |f| load f, true}
require 'capybara/dsl'
require 'capybara/rspec'
require 'turnip'
require 'turnip/capybara'
……略……
|
準備は整った。featureファイル(リスト16)と、それに関連するstepファイル(リスト17)を記述しよう。
# language: ja
機能: ユーザー管理
ユーザー管理を行いたい。なぜならサークル活動に参加するメンバーを管理する必要があるからだ。
シナリオ: 一覧画面から新規登録画面に移動する
前提 ユーザー管理の一覧画面を開く
もし "New User" リンクをクリックする
ならば ユーザー管理の新規登録画面が表示される
シナリオ: 登録画面で登録すると詳細画面に移動する
前提 ユーザー管理の新規登録画面を開く
もし "Name" に "アリス" と入力する
かつ "Age" に "16" と入力する
かつ "Create User" ボタンをクリックする
ならば ユーザー管理の詳細画面が表示される
|
なお、spec/features
フォルダーは自分で作成する。
step 'ユーザー管理の一覧画面を開く' do
visit '/users'
end
step '画面を目視' do
save_and_open_page
end
step ':name リンクをクリックする' do |name|
first(:link, name).click
end
step ':name ボタンをクリックする' do |name|
first(:button, name).click
end
step 'ユーザー管理の新規登録画面が表示される' do
current_path = URI.parse(current_url).path
expect(current_path).to eq '/users/new'
end
step 'ユーザー管理の詳細画面が表示される' do
current_path = URI.parse(current_url).path
expect(current_path).to eq "/users/#{User.last.id}"
end
step 'ユーザー管理の新規登録画面を開く' do
visit '/users/new'
end
step ':field に :value と入力する' do |field, value|
fill_in(field, :with => value)
end
|
なお、spec/steps
フォルダーは自分で作成する。
さっそくTurnipを実行してみよう。
$ bundle exec rspec spec/features/users.feature
ユーザー管理
登録画面で登録すると詳細画面に移動する
ユーザー管理の新規登録画面を開く -> "Name" に "アリス" と入力する -> "Age" に "16" と入力する -> "Create User" ボタンをクリックする -> ユーザー管理の詳細画面が表示される
一覧画面から新規登録画面に移動する
ユーザー管理の一覧画面を開く -> "New User" リンクをクリックする -> ユーザー管理の新規登録画面が表示される
Finished in 0.14995 seconds
2 examples, 0 failures
Randomized with seed 59374
|
もちろん次のようにrspec
コマンド単独で実行すれば、ユニットテストとインテグレーションテストが同時に実行される。このシンプルさはJenkinsを実行するうえで大きな味方となってくれるだろう。
$ bundle exec rspec
ユーザー管理
……略……
User
……略……
正常なデータがセットされた場合
should be valid
Finished in 0.1589 seconds
12 examples, 0 failures
Randomized with seed 2748
|
Gitを使ったリポジトリの登録
Git(ギット)は、CVSやSubversionと同じく、プログラムのバージョンを管理するためのソフトウェアだ。この連載で細かく使用方法は説明しないが、JenkinsでCI(継続的インテグレーション)を行ううえで非常に重要なツールである。ぜひ使い方をマスターしておこう。
ここでは先ほど作成したcircleアプリケーションをGitで管理することとする。リスト19のコマンドをcircle
ディレクトリで入力して、Gitのリポジトリを作成し、アプリケーションを登録しよう。
1
2
3
|
$ git init
$ git add .
$ git commit -m 'initial commit.'
|
第1回で説明した手順どおりにXcodeに付属するコマンドラインツールをインストール済みであれば、Gitを使える状態になっているはずだ。
- 1Gitのリポジトリを作成する。
- 2全てのファイルをリポジトリに登録可能な状態に設定する。
- 3リポジトリにコミット(=登録)したところ。
今後、Jenkinsからはこのリポジトリを参照してテストを実行することとする。
Jenkinsでのテスト実行
さて、アプリケーション単体でユニットテストおよびインテグレーションテストが実行できる状態になった。Jenkinsの設定を行い、テストを実行してみよう。
まずはJenkinsを起動しよう。インストール方法および起動方法は第1回を参照してほしい。
プラグインの設定
今回はGitリポジトリからソース一式をクローンして、rbenvでインストールしたRubyでテストを実行する。必要なプラグインを先にインストールしておこう。
起動したJenkinsの左のメニューから[Jenkinsの管理]をクリックし、それによる表示されるページの[プラグインの管理]をクリックしよう。
次に[利用可能]タブを選択し[フィルター]に「rbenv」と入力しよう(図3)。
「rbenv plugin」の[インストール]欄にチェックを付けて、[再起動せずにインストール]ボタンをクリックしよう。すると、次の画面のように表示される。
しばらく待つと、rbenv pluginがインストールされる。
このようにJenkinsは豊富なプラグインをインターネット経由で手軽にインストールできる。他のプラグインをインストールするときも同じ方法なので覚えておこう。
ジョブの作成
前回同様、メニューの[新規ジョブ作成]をクリックし、新しいジョブを作成する。今回は[ジョブ名]に「circle」と入力し、[フリースタイル・プロジェクトのビルド]を選択して[OK]ボタンを押そう(図5)。
次にジョブの設定を行おう。
まずはソースコード管理の設定を行う。
これには図6のように、[ソースコード管理]タブを開いて[Git]を選択し、[Repository URL]にGitのリポジトリを作ったディレクトリを入力しよう。今回はRailsプロジェクトのディレクトリを指定すればOKだ。
次はビルド環境とビルドの設定を行おう。これには図7のように、[ビルド環境]の中にある[rbenv build wrapper]をチェックし、[The Ruby version]欄には今回使用するRubyのバージョンである「2.3.1」を入力する。本稿の説明どおりにHomebrew経由でrbenvをインストールした場合は、[Preinstall gem list]の[高度な設定...]から[RBENV_ROOT]にデフォルトの「$HOME/.rbenv」ではなく「$HOME/.rbenv-jenkins」など別のディレクトリを指定して、Jenkins専用のrbenvを新たにGitリポジトリからインストールし直す必要がある。というのも、Homebrewがインストールした.rbenv
フォルダー内にはbin
フォルダーが存在しないなど、Gitリポジトリからrbenvをインストールした場合とディレクトリ構造が異なり、rbenv pluginがGitリポジトリからのインストールが前提となっているので、この構造の違いが原因となってエラーが発生してしまうからだ。
次に[ビルド環境]タブを開いて[ビルド手順の追加]セレクトボックスの中から[シェルの実行]を選択して、次のシェルスクリプトを入力しよう。
bundle install
bundle exec rake db:migrate
bundle exec rake db:test:clone
bundle exec rspec
|
お気づきだと思うが、ここで入力しているシェルスクリプトは、今までの開発中に入力したコマンドと同じである。開発中に何度も入力するコマンドを登録しておくだけで、Jenkinsが実行してくれるようになるわけだ。すばらしい!
シェルスクリプトの入力が終わったら[保存]ボタンを押しておこう。
ジョブの実行
さて、お楽しみの時間がやってきた。登録したジョブをさっそく実行してみよう。
Jenkinsのトップ画面からcircleジョブの実行ボタンを押してみよう(図8)。
今回のジョブの処理は簡単なものなのですぐに終了すると思う(※ただし初回は時間がかかる場合もある)。連載第1回の内容を思い出して実行結果を確認してみよう(図9)。うまくテストが実行されただろうか?
テストが成功すれば青色のボール*3が表示され、失敗すれば赤色となる。
- *3 テストの成功といえば青ではなく緑なのではなかろうか? 当然の疑問である。われわれ日本人は緑色の信号を「青信号」と言い、「青々とした緑が生い茂る」という謎の表現を平気で使う。そしてJenkinsの作者の川口氏は日本人である。こう考えれば青色のボールにも合点がいくのではないだろうか(注:筆者の妄想)。
自動実行
Gitリポジトリを監視することで、コミットされたら自動的にテストが実行されるように設定してみよう。
先ほど作成したジョブの[設定]をクリックし、[ビルド・トリガ]タブの中にある[SCMをポーリング]にチェックを付けよう。スケジュールにはcrontab形式でポーリング時間を入力する(図10)。
例えば5分ごとにコミットを確認するには、次のように入力する。
H/5 * * * *
|
新たな変更をコミットしてしばらく待つとテストが実行されるはずだ。
まとめ
アプリケーションの作成からテストの記述、そしてテストの自動実行まで急ぎ足で解説したが、いかがだっただろうか? RSpecとTurnipを組み合わせたテストは、今後、Railsでのテスト環境の主流になると筆者は考えている。ぜひJenkinsと併せて習得してもらいたい。
さて、開発マシンでJenkinsを動かしバックグラウンドでテストの自動実行を行うことで、開発効率が飛躍的に向上していることを感じ取れると思う。次回はJenkinsを使って、アプリケーションのデプロイを行う。堅牢なアプリケーションを素早くデプロイし、あなたの開発をより加速していこう!
1. Jenkinsをインストールして使ってみよう[Mac/Linux/Windows]
継続的インテグレーションツール「Jenkins」の使い方を基礎から解説する連載がスタート。初回は、Jenkinsの概要とインストール手順、簡単なジョブの登録方法を説明する。
2. 【現在、表示中】≫ Jenkinsでテストを実行してみよう+Rubyテストの基礎(RSpec&Turnip使用)
Jenkinsを使って小さなテストを自動実行して、開発スピードを飛躍的に向上させよう。また、MacでのRuby/Rails環境の構築方法から、テストフレームワーク「RSpec」とインテグレーションテスト環境「Turnip」を使ったテストの書き方までを解説する。
3. Jenkinsでアプリケーションをデプロイしてみよう
継続的インテグレーションの手順のうち、デプロイに焦点を当てて、テストの実行から、GitによるHeroku環境へのデプロイまでを自動化する方法を解説。Mac向けのGrowlを使って実行結果を通知する方法も説明。
4. Jenkins+Vagrantでテストを分散しよう
テストの分散は、環境を分けたい場合や速度を上げたい場合に役立つ。Vagrantで複数マシンのテスト環境を構築し、Jenkinsから複数マシンにまたがるテストジョブを実行してみよう。また、お勧めの便利なプラグインも紹介する。
5. Jenkins 2の新機能「Pipeline」を使ってみよう
何をやっているか分からない「Jenkinsおじさん」の作業を見える化しよう。Jenkins 2に新搭載されたPipelineを使えばパイプラインをコードで記述できるようになる。その基本的な使い方を解説。