【问题标题】:Why is ruby returning `true` for method call?为什么ruby为方法调用返回`true`?
【发布时间】:2017-08-02 16:23:53
【问题描述】:

所以这是我在 Rspec:w3ii.com: rspec 上找到的关于 rspec 助手的简要教程。这是示例的代码:

class Dog
   attr_reader :good_dog, :has_been_walked

   def initialize(good_or_not)
      @good_dog = good_or_not
      @has_been_walked = false
   end

   def walk_dog
      @has_been_walked = true
   end
end

describe Dog do
   def create_and_walk_dog(good_or_bad)
      Dog.new(good_or_bad).walk_dog
   end

   it 'should be able to create and walk a good dog' do
      dog = create_and_walk_dog(true)

      expect(dog.good_dog).to be true
      expect(dog.has_been_walked).to be true
   end
end

当我运行这个时,我得到这个错误:

NoMethodError:未定义方法“good_dog”为真:TrueClass
# ./dor.rb:22:in 'block in >'

我无法理解对 Dog.new() 的调用如何返回 true:TrueClass 对象而不是简单的狗。

【问题讨论】:

  • 我会非常小心地使用 w3ii 作为参考站点,因为它看起来质量相当低。有更好的places to start

标签: ruby-on-rails ruby rspec


【解决方案1】:

那是因为create_and_walk_dog 返回的walk_dog 方法返回

要从 create_and_walk_dog 方法返回一只狗,您需要类似

describe Dog do
   def create_and_walk_dog(good_or_bad)
      dog = Dog.new(good_or_bad)
      dog.walk_dog
      dog
   end

   it 'should be able to create and walk a good dog' do
      dog = create_and_walk_dog(true)

      expect(dog.good_dog).to be true
      expect(dog.has_been_walked).to be true
   end
end

或者扩展期望块:

describe Dog do
   it 'should be able to create and walk a good dog' do
      dog = Dog.new(true)

      expect(dog.good_dog).to be true
      expect {
        dog.walk_dog
      }.to change(dog, :has_been_walked).from(false).to true
   end
end

【讨论】:

  • 您还可以通过将self 添加为其中的最后一行代码,使walk_dog 成为可链接的方法。
  • 这将是使用tap(&:block) 方法的好例子,它产生block,然后返回对象本身。在这种情况下:Dog.new(good_or_bad).tap(&:walk_dog)
【解决方案2】:

我认为为了清楚起见,您可以/应该在此处使用 RSpec let 方法,而不是 RSpec 文件中包含的完整方法定义。让您的 _walk_dog_ 方法返回 self 就像我在另一个答案中看到的那样可以修复您当前的 RSpec 实现,但无助于您在潜在应用程序中的其他任何地方的流程。 bad 狗在 50% 的时间内随机返回 false _dog.walk_dog_ 或根本不合作的假设情况。

class Dog
  attr_reader :good_dog, :has_been_walked

  def initialize(good_or_not)
    @good_dog = good_or_not
    @has_been_walked = false
  end

  # Command to attempt walking a dog.
  # 
  # @api public
  # 
  # @example
  #   good_dog = Dog.new(true)
  #   good_dog.walk_dog # => Will always return true for good dogs.
  #   bad_dog = Dog.new(false)
  #   bad_dog.wal_dog # => 50/50 chance of true or false
  def walk_dog
    return @has_been_walked = true if @good_dog
    [true, false].sample
  end
end

describe Dog do

  let(:good_dog) { Dog.new(true) }

  it 'should always be able to walk a good dog' do
    expect(good_dog.walk_dog).to be true
  end

  it 'should track if the dog has been walked' do
    expect {
      good_dog.walk_dog
    }.to change(dog, :has_been_walked).from(false).to true
  end

end

也可以进行辩论,但除非您正在访问数据库或做一些相对耗时的事情,否则您也应该只针对每个规范声明一件事。

附:他们都是好狗布伦特

【讨论】:

    猜你喜欢
    • 2012-12-05
    • 1970-01-01
    • 2019-02-08
    • 2019-06-29
    • 1970-01-01
    • 1970-01-01
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多