en ja ja ja ja ja ja ja ja en ja ja ja ja ja ja ja ja ja ja en en ja en ja ja ja ja zh ja ja ja ja ja ja ja ja en ja ja ja ja en ja en ja en ja ja ja ja ja ja ja ja ja ja ja en ja ja ja ja ja ja ja pl ja ja ja ja ja ja ja ja ja en ja ja en ja ja vi ja sv eu ja en en hu ja ja en en pl ja ja jbo hbs_lat en ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja
RubyKaigi 2015:The history of testing framework in Ruby #rubykaigi - 2015-12-12 - ククログ
RubyKaigi 2015の2日目(2015年12月12日)にThe history of testing framework in RubyというタイトルでRubyのテスティングフレームワークの歴史を紹介しました。
歴史はRubyのテスティングフレームワークの歴史(2014年版)をベースにそろそろリリースされるRuby 2.3までの情報を追加したものになっています。RubyUnitについてもっと知りたい方はRubyUnitの開発者である助田さんが書いた[Ruby] RubyKaigi 2015(2日目): 遠回りするかなも読むとよいです。
Test::Unit APIについてはスライドの72ページ以降を参照してください。ざっくりというとTest::Unit APIは普通のRubyのコードを書くようにテストを書けることを大事にしている、ということを具体例を交えて説明しています。
ただし、フィクスチャーのAPIはそれほどRubyらしくありません。いつものRubyでは次のようにブロックを使って後処理の詳細を隠蔽できます。
File.open("README") do |file| # ... end # ← ブロックが終わったら開いたファイルを確実に閉じる
しかし、Test::Unit APIでは次のように別のメソッドで後処理を書かなければいけません。いつものRubyの書き方をできていないということです。
def setup @file = File.open("README") end def teardown @file.close end
この点についてFastly, Travis CI, GitHub 共催 RubyKaigi 前々夜祭で田中 哲さんから指摘がありました。そこで、発表までの間にtest-unit(発表を聞いた人なら区別をつけられるでしょうがgemのやつです)のmasterでは次のように使えるようにしました。
def setup File.open("README") do |file| @file = file yield # ここでtest_readが動く end # テストが終わったらファイルを閉じる end def test_read assert_equal("XXX", @file.read) end
ただ、@file = fileの部分がもやっとします。ふだんのRubyのコードではインスタンス変数に設定する使い方をしないからです。Test::Unit APIではインスタンス変数にテストで使うオブジェクトを設定するのは普通なので、テストコードという文脈では普通ですが、ふだんのRubyのコードという文脈では不自然なのです。
別の案として次のようなAPIも検討しましたが、やはりインスタンス変数に設定するところがもやっとします。(この書き方は既存のtest-unitですでに使えますが、非公開のAPIを使うことになるので実験用のコード以外では使わないでください。)
def run_test File.open("README") do |file| @file = file super end end
なお、環境変数を設定するような次のケースではsetupの中でyieldする書き方で違和感はありません。インスタンス変数を使わないからです。
def setup original_lang = ENV["LANG"] begin ENV["LANG"] = "C" yield ensure ENV["LANG"] = original_lang end end
File.openのようにブロックにデータを渡す使い方のときは、次のようにテストの中で実行した方がよいのかもしれません。
def test_read File.open("README") do |file| assert_equal("XXX", file.read) end end
APIについてなにかアイディアがある方はtest-unit/test-unitのissueにコメントをお願いします。RubyKaigi 2015中には次のフィードバックをもらいました。
setupではなくaroundなど違う名前のAPIにした方がよいのではないか
そもそもなぜsetupなのか。テスト毎にインスタンスを作るならinitializeでやるのが普通ではないか
テストメソッド(この例ではtest_read)が引数を受け取るようにしたらよいのではないか(そうすればインスタンス変数に設定する必要はなくなる)
yieldにオブジェクトを渡したら自動でインスタンス変数に設定するのはどうか
違う名前のAPIはよいかもしれませんが、aroundはなじまないのが悩ましいところです。Test::Unitの既存のフィクスチャーのAPIはsetup/teardownというように役割を名前にしているのでaroundというように順序を名前にするのはなじまないのです。RSpecのようにbefore/afterというように順序を名前にしているならなじむのかもしれません。
なお、setupの中で後処理も実行されることがもやっとするのでsetupではない名前がよさそう、ということであれば、そこは心配しなくてもよいです。File.openのように本処理を名前にしているメソッドがブロック付きで呼ばれたら後処理をするようになることは普通のRubyのコードだからです。setupも本処理の名前です。
initializeでやるのはよいかもしれませんが、後処理をするタイミングを作れないのが悩ましいところです。普通のRubyのコードではFile.open {...}のように処理の範囲を明示しないときはGCのタイミングで後処理が動きます。テストでは他のテストに影響を残さないように、テストが終わったら確実に後処理を実行しておきたいです。
テストメソッドが引数を受け取ると複数のセットアップ処理を指定したときに破綻しそうな点が悩ましいところです。
yieldにオブジェクトを渡すと自動でインスタンス変数を設定するのは可読性が悪くなりそうなところが悩ましいところです。
ちなみに、setupでyieldしても動くようにする仕組みは次の擬似コードのように実装しています。
def run_test block_is_called = false setup do block_is_called = true test_read end test_read unless block_is_called end
先日RubyKaigi 2015にスピーカー・スポンサーとして参加予定でオススメした通り、咳さんのActor, Thread and meが非常に興味深かったです。
bartender(咳フリークはこの名前を聞くとDivを思い出すでしょう)はRubyWorld Conference 2014で話した同期っぽいAPIの実装と同じようなものでした。いまだに着手していませんが、これをベースに複数の通信を並行して進めるときにそれっぽく書けそうなAPIがあるとよさそうと検討していたのでした。
クリアコードがシルバースポンサーとして応援したイベント「RubyKaigi 2015」での発表「The history of testing framework in Ruby」の内容を簡単に紹介しました。また、オススメの咳さんの発表についても少し触れました。
今回、スポンサーとして参加した成果はまだわかりません。配布物としてリーダブルコードワークショップのチラシとGroonga族のステッカーを置いておきました。参加者が帰った後に残った分を回収しましたが、どちらもほぼなくなっていました。興味があった方はぜひお問い合わせください。
現在クリアコードではソフトウェア開発者を募集しています! フリーソフトウェア開発での開発の仕方をベースに、成果や知識を公開し共有しながら業務に携われます。
Groongaプラグイン自作入門
Firefoxを意図的にクラッシュさせる方法
Apache Arrow
milter manager
ククログの記事はCC BY-SA 4.0とGFDLのデュアルライセンスで自由に利用できます。
クリアコードはプログラミングが楽しいソフトウェア開発者を1名募集しています。
クリアコードは「クリアコードをいい感じにする人」を1名募集しています。
クリアコードはフリーソフトウェア開発で培った技術力を提供しています。特にMozilla製品(Mozilla FirefoxとMozilla Thunderbird)とRubyとGroonga(全文検索)に関連した開発を得意としています。