Skip to content.

Sections
Personal tools
You are here: Home » コミュニティ » masarl memorial » masarl.cocolog-nifty.com » main » 2004 » 10 » Cotton Bolls: RubyUnit実践講座―開発環境編

Cotton Bolls: RubyUnit実践講座―開発環境編

Document Actions

« テストデータのセットアップ | トップページ

2004.10.31

RubyUnit実践講座―開発環境編

RubyのTest::Unitモジュールは,TestRunnerを全く意識しないでテストコードが書ける.例えばテストファイルfoo-test.rbがあって

#! ruby
require 'test/unit'

class FooTest < Test::Unit::TestCase
  def test_1
    assert_equal(2, 1+1)
  end
  def test_2
    assert_equal(1, 2-1)
  end
end

と書かれていれば

$ ruby foo-test.rb

とするだけで実行できてしまう.特定のテストメソッドだけ実行したいのなら--nameオプションを使って

$ ruby foo-test.rb --name=test_2

とするだけでいい.foo-test.rbにはTestRunnerがどこにもないのに動いてしまう.素晴らしい.

複数のテストファイルがあった場合はどうだろう.このときは,all-tests.rbを作ればよい:

#! ruby
require 'foo-test'
require 'bar-test'
require 'baz-test'

その後all-tests.rbを実行する:

$ ruby all-tests.rb

これだけだ.all-tests.rbを作るのが面倒なら,ワンライナーで実行することもできる.すなわち

$ echo '%w(foo-test bar-test baz-test).each { |f| require f }' | ruby

とすればいい(なぜか-eオプションを使う方法ができなくなっている).

ただ,こういった方法はテストファイルが増えてくると管理が面倒になってくる.そこで今回はGNU Makeを使ってテストを自動化する方法を紹介しよう.

一般にxUnitでは,次のテストが実行できれば十分だ:

  • プロジェクト全体のテスト
  • あるディレクトリ以下全体のテスト
  • あるテストファイルのテスト
  • あるテストファイル内のテストメソッドのテスト

そのためまずテストファイルのネーミングルールを決める.ここでは*-test.rbとしよう.Makeターゲットの仕様は次のようなものでいいだろう:

# プロジェクト全体を実行
$ make test all=true

# カレントディレクトリ以下全体を実行
$ make test

# テストファイルfoo-test.rbのみ実行
$ make foo.test

# foo-test.rb内のテストメソッド:test_2のみ実行
$ make foo.test method=test_2

さて,ディレクトリ階層にまたがったMakefileを作るため,common.mkの方法を使う.common.mkの方法とは,プロジェクトのルートディレクトリにcommon.mkを置き,各ディレクトリのMakefileからcommon.mkをインクルードする方法だ.こうすることでプロジェクト全体のMakefileを統一できる.

ルートディレクトリ直下のMakefileは

ROOT_DIR = .
include $(ROOT_DIR)/common.mk

と書き,ルートディレクトリから二階層下のMakefileでは

ROOT_DIR = ../..
include $(ROOT_DIR)/common.mk

と書く.ROOT_DIR変数にルートディレクトリへの相対パスを設定し,common.mkをインクルードするわけだ.

というわけで,ここからはcommon.mkの具体的な内容について書いていくことにしよう.ROOT_DIRにルートディレクトリのパスが設定されていることを覚えておいてほしい.

まずはrubyコマンドのオプションを設定しよう.ルートディレクトリにパスが通っていなければならないので,次のようになる:

ruby-flags = -Ks -I$(ROOT_DIR)
ruby-command = ruby $(ruby-flags)

-Ksオプションはソースの漢字コードがSJISであることを示すオプションだ.この辺は実際の開発に応じて変更してほしい.

まず簡単なターゲットから片付けていく.テストファイルまたはテストメソッド単体での実行だ:

%.test:
	$(ruby-command) $*-test.rb $(if $(method),--name=$(method))

$(if ...)ファンクションは,$(method)に値があるときだけ第二引数に展開される.
このターゲットでMakeを実行してみよう:

$ make foo.test
ruby -Ks -I. foo-test.rb 
Loaded suite foo-test
Started
..
Finished in 0.0 seconds.

2 tests, 2 assertions, 0 failures, 0 errors

$ make foo.test method=test_2
ruby -Ks -I. foo-test.rb --name=test_2
Loaded suite foo-test
Started
.
Finished in 0.0 seconds.

1 tests, 1 assertions, 0 failures, 0 errors

最初のコマンドがfoo-test.rbの実行で,次のコマンドがtest_2のメソッドを実行したことになる.

次にディレクトリ以下のテストファイルを一括で実行するためのターゲットを定義しよう.テストファイルをすべて列挙するには,findコマンドを使えばよい:

test-files = $(shell find . \
	-name '*-test.rb' \
	-and -not -path '*/CVS/*' \
	-print)

ここで,CVSを考慮してCVSディレクトリは除外した.このときディレクトリ以下をテストするターゲットは次のように書ける:

.PHONY:test
test:
	ruby -e '%w($(test-files)).each { |f| require f }'

プロジェクト全体のテストファイル実行はどうだろうか? 上のtest-files変数でfindコマンドのディレクトリ指定をROOT_DIRにすればいい:

all-test-files = $(shell find $(ROOT_DIR) \
	-name '*-test.rb' \
	-and -not -path '*/CVS/*' \
	-print)

さきほどと同じような変数定義になってしまったので,ファンクションを使おう.ここではfind-test-filesという名前にする:

find-test-files = $(shell find $1 \
	-name '*-test.rb' \
	-and -not -path '*/CVS/*' \
	-print)

このとき,

test-files = $(call find-test-files,.)

とすればカレントディレクトリ以下のテストファイルが設定されるし,

test-files = $(call find-test-files,$(ROOT_DIR))

とすればプロジェクト全体のテストファイルが設定される.プロジェクト全体のテストではall変数が定義されることを思い出せば

test-files = $(call find-test-files,$(if $(all),$(ROOT_DIR),.))

のようにすればいいことがわかる.

以上を踏まえて,common.mkの中身をすべて書いてみよう:

ruby-flags = -Ks -I$(ROOT_DIR)
ruby-command = ruby $(ruby-flags)

find-test-files = $(shell find $1 \
	-name '*-test.rb' \
	-and -not -path '*/CVS/*' \
	-print)

.PHONY:test
test:test-files = $(call find-test-files,$(if $(all),$(ROOT_DIR),.))
test:
	echo '%w($(test-files)).each { |f| require f }' | $(ruby-command)

%.test:
	$(ruby-command) $*-test.rb $(if $(method),--name=$(method))

想像以上に簡単ではないだろうか?
なお,実際にmakeコマンドでテストするときは,引数指定が面倒なのでEmacs Lispのコマンドを使っている(xunit.el).この辺の話はまた機会があれば紹介したいと思う.

|

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/1811341

この記事へのトラックバック一覧です: RubyUnit実践講座―開発環境編:

» 大変残念 from えとせとら
大変残念です。そしてお悔み申しあげます。 続きを読む

受信: April 26, 2005 11:37 PM

» 弔辞 from L'eclat des jours
ご冥福をお祈りするとともに、深い感謝の気持ちを捧げます。 続きを読む

受信: April 27, 2005 02:34 AM

コメント

Rubyの、OOPの、そしてagileの同志を失ったことを心より残念に思います。同じ時代にネットに生きた証としてお悔やみの言葉をここに記します。

名前: 越水智之 | April 26, 2005 10:24 PM

コメントを書く