如何使用rspec测试DSL API方法

时间:2014-01-03 02:25:04

标签: ruby rspec

我想测试一个方法接收一个块...但我的rspec存根返回(no args)

这是一个人为的例子......

class Foo
  def self.bar &block
  end
end

describe Foo do
  before do
    Foo.stub(:bar)
    Foo.bar { 'foo'}
  end
  it 'should' do
    expect(Foo).to have_received(:bar).with(kind_of(Proc))
  end
end

导致......

  1) Foo should
     Failure/Error: expect(Foo).to have_received(:bar).with(kind_of(Proc))
       <Foo (class)> received :bar with unexpected arguments
         expected: (#<RSpec::Mocks::ArgumentMatchers::KindOf:0x1022a7b20 @klass=Proc>)
              got: (no args)

修改

这是Peter实施解决方案的一个毫无意义的例子......

foo.rb

class Foo
  def self.setup &block
    @setup ||= block
  end
  def setup
    instance_eval &self.class.setup
  end
end

bar.rb

# DSL designed class
class Bar < Foo
  setup do
    # setup Bar instances here
  end
end

bar_spec.rb

# Need to make sure DSL classes are correctly implemented
describe Bar do
  after do
    load 'bar'
  end

  it 'should define .setup' do
    expect(Bar).to receive(:setup){ |&block| expect(block).to be_a(Proc) }
  end
end

2 个答案:

答案 0 :(得分:2)

我不相信有任何方法可以验证事件后是否传递了一个块,但如果您使用正常的执行前期望值,则可以按如下方式检查:

class Foo
  def self.bar &block
    puts 'DO NOT RUN'
  end
end

describe 'Foo#bar' do
  it 'should confirm a block is passed' do
    expect(Foo).to receive(:bar) {|&block| expect(block).to be_a(Proc)}
    Foo.bar {}
  end
  it 'should confirm a block is not passed' do
    expect(Foo).to receive(:bar) {|&block| expect(block).to be_nil}
    Foo.bar
  end
end

如果你不介意实际屈服于该块,那么你可以使用.and_yield,如果一个块不存在,这将产生一个期望错误。

class Foo
  def self.bar &block
  end
end

describe Foo do
  before do
    Foo.stub(:bar), y
  end
  it 'should' do
    expect(Foo).to receive(:bar).and_yield
    Foo.bar {}
  end
end

答案 1 :(得分:0)

为了测试一个块被调用而不必运行它并查看yield是否失败,我决定重新打开该类并利用类var。这是一个临时的解决方法,因为(IMO)rspec应该负责此功能。

class Foo
  def self.bar &block
    puts 'DO NOT RUN'
  end
end

describe Foo do
  before do
    class Foo
      def self.bar &block
        Foo.send(:class_variable_set, :@@bar_val, block)
      end
      Foo.bar {} # this line is dynamic in my real specs :)
    end
  end

  after :all do
    load 'foo' # to revert back to the original class
  end

  it 'should' do
    expect(Foo.send(:class_variable_get, :@@bar_val)).to be_a Proc
  end
end
相关问题