在编写rspec测试用例时如何覆盖ruby方法的局部变量?

时间:2017-12-21 09:46:46

标签: ruby-on-rails ruby unit-testing rspec

现有的Ruby代码:

def book_details
  book_count = Book.count
  while (book_count > 1)
    # Do something
  end
end

我想写一个rspec测试用例,它在book_details函数中设置book_count值。可能吗?如果是,怎么样?

到目前为止,我所尝试的是:

it 'Should return 1 book details only' do
  allow(Model).to receive(book_count).and_return(1)
  # Do something
end

但是这给#n / #p>提供了错误'未定义的局部变量或方法`book_count'

3 个答案:

答案 0 :(得分:0)

让我们说,book_count = 1000是红宝石代码,你想用rspec将它重置为10,然后下面就可以了:

allow(Book).to receive(:count).and_return(10)

以上将根据您对rspec的期望进行计数。

另外,具体而言,rspec contexts rspec是针对methods编写的,而不是针对local variables。 因此,rspec中的测试方法期望。

以下是rspec的简单method示例:

class Book

  def book_details
    book_count = Book.count
    while (book_count > 1)
      puts 'Book name'
    end
  end

end

describe 'Books' do

  describe '#book_details' do

    context 'when Books are less than one' do

      it 'should not return book details' do
        book_details.should eq 0
        book_details.should_not eq 'Book name'
      end

    end

    context 'when Books are more than one' do

      before do
        FactoryGirl.create(:book)
      end

      it 'should return book details' do
        book_details.should_not eq 0
        book_details.should eq 'Book name'
      end

    end

  end

end

答案 1 :(得分:0)

答案基本上是:不要。

如果您觉得需要在方法中间覆盖变量,那么您做错了;该方法责任太多,需要分解。

在这种情况下,让测试工作的一种快捷方式是:

allow(Book).to receive(:count).once.and_return(1)

或者,稍微更简洁的方法是将该调用提取到一个新方法中,因此您只能将您所拥有的行为隐藏起来" - 类似于:

class Foo
  def book_details
    while (book_count > 1)
      # Do something
    end
  end

  def book_count
    Book.count
  end
end

# In your test:
let(:foo) { Foo.new }
allow(foo).to receive(:book_count).once.and_return(1)

...但事实上,你应该真正在这里做什么,理想情况下,正确地测试方法,就是不要嘲笑任何东西!由于您的代码与数据库交互,因此您的测试应为代码创建真实记录以进行交互:

# Using FactoryBot, for example:
let!(:books) { create_list(:book, 5) }

答案 2 :(得分:0)

Book.stub(:count).and_return(10)