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

问题描述 投票:0回答:3

现有的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

但是这给#错误'未定义的局部变量或方法`book_count'#

ruby-on-rails ruby unit-testing rspec
3个回答
0
投票

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

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

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

另外,特别是你的rspec contextsrspec是为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

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) }

0
投票
Book.stub(:count).and_return(10)
© www.soinside.com 2019 - 2024. All rights reserved.