櫓日誌

<< RSpec | main | Rubyで内包表現 >>
スポンサーサイト

一定期間更新がないため広告を表示しています

| スポンサードリンク | - | | - | - |
RSpecの拡張

RSpecのスタックの例だと、スタックの仕様を「空」、「要素が1つだけ」、「ほとんど満杯」、「満杯」の4つのコンテキストで表しているんだけど、これだと要素が2や3のときの場合がなくて、仕様としては不十分じゃないだろうか。これはたぶんスタックの振る舞いが変わる4つの境界をコンテキストとして選んでいるからであって、仕様というよりはテストケースっぽいような。

仕様を記述するのであれば、仕様と上のような仕様の具体例を分けて考えたいと思う。たとえばスタックであれば「空」、「満杯」、「空でもなく満杯でもない」の三つをコンテキストする。この場合のコンテキストは抽象的で、一つ以上の具体例に対応する。「空」の場合は一つだけだけど、「満杯」や「空でもなく満杯でもない」は、いろいろな具体例がありえる。要素が一つだけのスタック、ほとんど満杯のスタックは、「空でもなく満杯でもない」コンテキストの具体例の一種だ。

試しに、一つのコンテキストで複数の具体例を表せるように、RSpecを拡張してみた。add_instanceで具体例を追加できる。specifyはcontextの具体例の数だけ繰り返し実行する。スタックの場合、下のような感じになるけど、もっときれいに仕様っぽく書けないかな。そもそも仕様っぽさってなんだって話になってくるのか。。

require File.dirname(__FILE__) + "/stack"

module Spec
  module Runner
    class Context
      def add_instance(&block)
        @instances ||= []
        @instances << block
      end
      
      alias org_run run
      
      def run(reporter, dry_run=false)
        if (@instances == nil)
          org_run(reporter, dry_run)
        else
          reporter.add_context(@name)
          @instances.each do |instance|
            @specifications.each do |specification|
              specification.run(reporter, instance, @teardown_block, dry_run)
            end
          end
        end
      end
    end
  end
end


=begin
Stackの仕様を、スタックの状態に応じて三つのコンテキストに分ける
(1)空
(2)空でも満杯でもない
(3)満杯
=end

context "空" do
  
  # コンテキストのインスタンスは一つだけ
    add_instance do 
    @stack = Stack.new
  end
  
  specify "should accept an item when sent push" do
    lambda { @stack.push Object.new }.should_not_raise
  end
  
  specify "should complain when sent top" do
    lambda { @stack.top }.should_raise StackUnderflowError
  end
  
  specify "should complain when sent pop" do
    lambda { @stack.pop }.should_raise StackUnderflowError
  end
end

context "空でもなく満杯でもない" do
  
  # コンテキストのインスタンスを複数定義
#  (1..9).each do |size|
  [1,9].each do |size|
    add_instance do
      @stack = Stack.new
      size.times do |i|
        @stack.push (i+1)
      end
      @last_push_member = size
    end
  end

  specify "should accept an item when sent push" do
    lambda { @stack.push Object.new }.should_not_raise
  end

  specify "should return top when sent top" do
    @stack.top.should_be @last_push_member
  end

  specify "should not remove top when sent top" do
    @stack.top.should_be @last_push_member
    @stack.top.should_be @last_push_member
  end

  specify "should return top when sent pop" do
    @stack.pop.should_be @last_push_member
  end

  specify "should remove top when sent pop" do
    @last_push_member.times do
      @stack.pop
    end
    lambda { @stack.pop }.should_raise StackUnderflowError
  end
end

context "満杯" do
  
  # コンテキストのインスタンスを一つだけ定義
  add_instance do
    @stack = Stack.new
    (1..10).each { |i| @stack.push i }
  end

  specify "should complain on push" do
    lambda { @stack.push Object.new }.should_raise StackOverflowError
  end
  
  specify "should return top when sent top" do
    @stack.top.should_be 10
  end
  
  specify "should not remove top when sent top" do
    @stack.top.should_be 10
    @stack.top.should_be 10
  end
  
  specify "should return top when sent pop" do
    @stack.pop.should_be 10
  end
  
  specify "should remove top when sent pop" do
    @stack.pop.should_be 10
    @stack.pop.should_be 9
  end
end
| YAGURA | - | 01:09 | comments(0) | trackbacks(0) |
スポンサーサイト
| スポンサードリンク | - | 01:09 | - | - |









http://yaglog.jugem.jp/trackback/34
   1234
567891011
12131415161718
19202122232425
262728293031 
<< March 2017 >>

このページの先頭へ