Showing posts with label RSpec. Show all posts
Showing posts with label RSpec. Show all posts

Saturday, 15 December 2012

Mongoidを使ってRSpecでテストした時にFactoryGirlでバリデーションエラーが無くならない

Mongoidを使ってアプリケーションを作っていて、RSpecでテストした時にFactoryGirlでバリデーションエラーが無くならないという事がありました。

一時的にtestの環境ではヴァリデーションをスキップするという方法でしのいでいたのですが、実はspec_helperにDBのコレクションをbefore(:each)のタイミングでドロップするという設定が必要だという事でした。これを実行してみると、問題無くバリデーションエラーがとれました。mongoid-rspecのドキュメンテーションにもこんな事は書いていなかったと思うし、ドキュメントの読み方が悪いのでしょうか…。

http://adventuresincoding.com/2012/05/how-to-configure-cucumber-and-rspec-to-work-with-mongoid-30

database_clearnerのgemを導入したタイミングのどこかで自動でテストの時にデータベースのコレクションを削除してくれるスクリプトも導入されるのかと思ったらそんなことは無い様ですね…。

Thursday, 8 November 2012

RailsとRubyのエラーハンドリングの違い

ウェブアプリケーションを作っていると

if !object.method
  do_this
else
  do_that
end

という方法でユーザを誘導する習慣が付いていますが、Rubyで組み込みやデスクトップアプリケーションなどを開発する際には下のようにする人が多いのではないでしょうか?

begin
  do_this
  do_that
rescue
  error_handling_method($!)
end

こうしておいて

def do_this
  raise 'Specific error message' if !some_method
end

などとそれぞれのメソッドの中でRuntime errorを発生させれば最後のrescueの所でまとめてエラーを処理できるので便利でした。例えばSTDOUTに表示させるとか、ログにまとめるとか、メールでエラーを報告するなどなど。

ちなみにRSpecではこのサイトに書いてある通り

it "should raise" do
 expect{Object.non_existent_message}.to raise_error(NameError) end

とすればテストが書けます。

Railsでも同じようにエラーの処理はできると思いますが、通常begin, rescue, endは使わないですね。ディベロッパー向けのAPI以外では、ウェブアプリケーションはエラーメッセージは極力詳細は出さない事もセキュリティー上大切なのでこのような設計になるのでしょうね。例外が発生したら多くの場合シンプルにbreakして500を返しますもんね…。ウェブサービスでもREST APIを作る人はもっと複雑なエラーハンドリングを開発しているんでしょうね。お疲れさまです。

Monday, 29 October 2012

SinatraとRSpecで開発(ちょっとしんどい)

ここ2日程SinatraとRSpecを使って、1ページウェブサイトの制作をしていました。

Sinatraはとてもシンプルなのが好きで使っているのですが、少しやる事が複雑になると一つずつrequireを追加していく必要があります。フォームを設置する、外部APIを使用する、テストを書くという程度の制作になればSinatraではなくてRailsにしたほうがかなり時間を抑えて開発できるのではないでしょうか。小さな規模のサイトなのにかなり時間がかかりました。

例えばURLのパースにはURIを使い、外部APIを使うにはNet:HTTPを使い、メールの送信にはPonyかMailなどのgemを使用、viewのヘルパーもデフォルトでは便利なものが多くないので、Sinatra_moreのgemを引っ張ってくるという具合です。RSpecのテストをする際にもデフォルトではassignsやrender_templateなどの何気なく使用しているマッチャーも無く、カスタマイズが必要でした。メールの送信もあまりマニュアルが整備されていないgemを使う必要があり、コードを読みにいったりする必要がありました。

今回はいかにRoRが皆に支持されていろんな便利なツールを実装しているか知る良い機会になりました。それはそれでありがたい経験です。

Thursday, 19 July 2012

メソッドチェーンをRSpecでテストする

RSpecでメソッドチェーンをテストするのにどうやったものか手間取りました。

例えば

obj.do1.do2.do3

とあったときには

一気に

obj.stub(:do1.do2.do3)

とstubできないので、

res1 = stub()
res2 = stub()
obj.stub(:do1).and_return(res1)
res1.sbub(:do2).and_return(res2)

とそれぞれstubを作る必要がある様です。

メソッドチェーンはRuby(とRSpec)では推奨されないやり方なのでしょうか…

Saturday, 30 June 2012

Test Double について

TDD, BDDは使い慣れていない用語や普段使っている言語とは異なるソフトウェアサイエンスでの用法があるので、用語の理解が一つのハードルであると感じます。

この辺りはかなりソフトウェアエンジニアリングではなく、ソフトウェアサイエンスの領域に入ってくるんでしょうね。最近はビジネスに関連してソフトウェアエンジニアリングのアプリケーションばかりをしていますが、学生の頃にはサイエンスの方をしていたのが懐かしく感じます。

"Test Double"もその一つではないでしょうか?"Test Double" G. Meszarosという人が考えた言葉なそうです。本人の書いた記事にその内容が書かれています。是非オリジナルを当たってください。個人的に著者の言葉の使い方にはprecisionが欠けている箇所がある気がしますが。



Doubleというのは英語ではいわゆるそっくりさんのことですね。G. Meszarosの原文ではスタントマンを例にとってきています。上の図に表される様にG. Meszarosの定義では、Test DoubleにはTest Stub, Test Spy, Mock Object, Fake ObjectとDummy Objectが含まれます(このDummy Objectは正確にはTest Doubleには含まれないそうですが)。要は"Test Double"とはこれらの用語を総称した言葉ですね。

用語
SUT: System Under Test テスト対象のシステム
DOC: depended-on component 異存しているコンポーネント
indirect output: 公開APIでは見れないが、他のコンポーネントに送られているSUTからのアクション

以下、それぞれの意味というか使い方です。

- Test Stub: SUTから送られてくるメッセージを受け取るために使用。indirect outputを正常に受け取らないとSUTが正常に動作しないなどの場合に使用。

- Test Spy: SUTから送られてくるメッセージを受け取るために使用というのはTest Stubと同様だが、Test SpyはSUTから送られてきたindirect outputの内容を記録して、後でバリデーションに使用できるようにする。

- Mock Object: Test Spyと同様に使用。原著からは私はTest StubとTest Spyの違いが見つけられませんでした。

- Fake Object: 実際のDOCの疑似コンポーネント。実際のDOCと似た動きをするが、まだ実際のDOCが用意できていない時に使用する。また、実際のDOCではデータベースの読み込みに時間がかかりテストに適していないという場合には、Fake Objectのハッシュオブジェクトにデータを収納してテストに用いる。

- Dummy Object: SUTがパラメータにオブジェクトを必要とするときに渡すオブジェクト。中身の無いメソッドを実装したnull object 参照でも問題無い。Dummy Objectは原著では厳密にはTest Doubleではなく、Literal Value、Derived Value、Generated Valueに属するとされている。

Wednesday, 20 June 2012

RoRとmongoidとRSpecでTDDことはじめ

RoRとmongoidとRSpecでテストを動かそうとしたところ、下のようなエラーメッセージが出ました。

undefined method `fixture_path=' for # (NoMethodError)

これに関してはすでに解決している人がいたので、ググって解決です。