研究でdRubyを使っているのですが、そのとき詰まったのがテストの方法で、しばらく悩んでしまった
今回は僕の使っている方法を書き残しておこうと思う
ちなみに、RSpecの使用を前提としている
通信をおこなわない場合
まずは、通信を行わない場合について考える。
単純に、ちゃんとdRubyサービスを開始しているかをテストするには、should_receiveを使って以下のように書く
it 'should connect server' do uri = 'druby://...' DRb.should_receive(:start_service).with(uri, @server) @server.start end
@server.startの中でDRb.start_serviceが呼ばれなければエラーになる。このときwithで@server自身を指定しているのは、内部で自分自身をフロントにしてdRubyサービスを開始するようにしているからである
フロントになるオブジェクトはサーバクラスの中で生成される場合はテストがしにくくてたまらないので、そうならないように設計すると良い
次に、クライアンと側だが、これはサーバと同じでDRbObjectにたいして、should_receive(:new_with_uri)を呼ぶだけなのでコードは割愛する
実際の内部動作をテストする場合もモックを使うと上手くいく
この場合、欲しい情報は、通信を行った後に得られる結果のみである。そしてその結果をうまく処理できているかを見たい。
describe client do before do @unformatted_data = ... @formatted_data = xxx @server = mock('server', :get => @unformatted_data) end it 'syould return formatted server return value' do @client.should_receive(:format_data).with(@unformatted_data).and_return(@formatted_data) data = @client.get_data data.should == @formatted_data end end
beforeの中でサーバのモックを作り、スタブを定義している。こいつはgetが呼ばれたら@unformatted_dataを返すだけだが、実際はDRbObjectであることを想定している
exampleの中では@clientがformat_dataを呼ぶことを期待している。さらに返す値も差し替えているので、もし内部でformat_dataが呼ばれたら、get_dataの返り値は@formatted_dataのはずであるので、それも確かめている。
このようにして、通信を行わずにテストをするときはモックとスタブ、そしてshould_receiveを使うと良い
通信を行う場合
通信をさせたい場合は以下のようなヘルパメソッドを書いておけば便利である
def on_service(front = [], port = 12345, host = 'druby://localhost') uri = "#{host}:#{port}" DRb.start_service uri, front yield ensure DRb.stop_service end
このメソッドにブロックを与えると、その中では指定したホスト、ポート、フロントのdRubyサービスが有効になっている
on_service({:name => 'tomohiro', :age => 22}) do @server = DRbObject.new_with_uri('druby://localhost:12345') @server.keys #=> [:name, :age] p @server[:name] #=> "tomohiro" end
これを用いて、サーバのブラックボックステストなどを行っていく
まとめ
- モック、スタブを使った方法をみた
- ヘルパを使って実際にサービスとやりとりする例をみた
通信を行ったり、スレッドを使ったりする場合はテストが難しいことがあるので、まずは、テストし易い設計を考える。それからどうすればテストできるかを考えると良い