【问题标题】:Having trouble stubbing a class method in RSpec / Rails (and using dynamic returns on stubs)在 RSpec / Rails 中存根类方法时遇到问题(并在存根上使用动态返回)
【发布时间】:2012-05-18 15:11:23
【问题描述】:

晚上好,

我试图在我的“模拟”类中测试一个相当长的方法,它调用类方法“is_male_alive?”和“is_female_alive?”在我的“年龄”课上几百次。这些类方法的返回值基于统计信息,我想将它们存根以返回特定值,以便我的测试每次运行都相同。

年龄.rb:

...

def is_male_alive?(age)
  return false if age > 119
  if (age < 0 || age == nil || age == "")
    return false
  end    
  death_prob = grab_probability_male(age)
  rand_value = rand
  rand_value > death_prob
end

...

(女版基本相同,只是一些不同的常数)

在我的“模拟”课程中,我执行以下操作:

def single_simulation_run

  ...
  male_alive = Age.is_male_alive?(male_age_array[0])
  female_alive = Age.is_female_alive?(female_age_array[0])
  ...
end

在模拟的每次迭代中 - 基本上它只是传递一个年龄(例如 is_male_alive?(56) )并返回真或假。

我想把这两种方法去掉,这样:

  1. is_male_alive?对于小于 75 的任何参数返回 true,否则返回 false
  2. is_female_alive?任何小于 80 的参数返回 true,否则返回 false

我已经尝试了以下方法,看看我是否有能力将其存根 (simulation_spec.rb):

Age.should_receive(:is_male_alive?).exactly(89).times
results = @sim.send("generate_asset_performance")

但我收到以下错误:

 Failure/Error: Age.should_receive(:is_male_alive?).exactly(89).times
   (<Age(id: integer, age: integer, male_prob: decimal, female_prob: decimal) (class)>).is_male_alive?(any args)
       expected: 89 times
       received: 0 times

我也不知道如何设置它,以便根据参数动态生成存根返回值。有没有办法用 proc 做到这一点?

有没有办法模拟整个 Age 类(而不是仅仅模拟 Age 类的单个实例?)

感谢您的帮助!!

更新 1

看起来调用这个方法有问题......这真的很混乱。为了真正查看它是否被调用,我在方法中抛出了“raise ArgumentError”。

开发环境(控制台):

1.9.3p125 :003 > sim = Simulation.last
1.9.3p125 :004 > sim.generate_results
  --->  ArgumentError: ArgumentError

所以它显然是在开发环境中调用这个方法,因为它抛出了参数错误。

在我的测试中再次运行它,它仍然说该方法没有被调用...我在下面使用你的代码:

Age.should_receive(:is_male_alive?).with(an_instance_of(Fixnum)).at_least(:once) { |age| age < 75 }

我也试过了

Age.should_receive(:is_male_alive?).with(an_instance_of(Fixnum)).at_least(:once) { raise ArgumentError }

有什么想法吗?

【问题讨论】:

  • 响应您的更新:很难说为什么没有调用该方法,因为您省略了大部分代码。你能展示你剩下的测试代码和generate_results方法吗?

标签: ruby-on-rails testing rspec mocking stubbing


【解决方案1】:

你可以使用方块。请参阅 rspec 的消息期望文档中的任意处理:http://rubydoc.info/gems/rspec-mocks/frames

Age.should_receive(:is_male_alive?).with(an_instance_of(Fixnum)).at_least(:once) { |age| age < 75 }
Age.should_receive(:is_female_alive?).with(an_instance_of(Fixnum)).at_least(:once) { |age| age < 80 }

【讨论】:

  • 我投了赞成票,但看起来提问者应该使用 stub 而不是 should_receive
  • 两者都可以。似乎询问者还想确保收到消息并且存根不会对此进行测试。
  • 哇——太快了。谢谢! proc 部分看起来正是我正在寻找的。但是,仍然存在不调用该方法的问题。我认为一定有其他奇怪的事情发生......我已经将“logger.error”和“puts”放入Age.is_male_alive?方法并且在我的测试期间它没有打印任何东西......虽然看到整体模拟的结果正在经历,但不知道它是如何工作的!赞成,因为我确定我做错了什么,让我先弄清楚,然后再接受。
  • 当您使用stubshould_receive 时,它会阻止方法调用冒泡到您的方法定义——因此看起来好像方法本身没有被调用。尝试在其中一个块内登录。
  • 哦,伙计 - 我发现我做错了什么让方法被调用,男孩是愚蠢的。你的方法效果很好。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-01
  • 2021-09-03
  • 1970-01-01
  • 2014-09-23
  • 2015-08-31
  • 2021-03-15
  • 1970-01-01
相关资源
最近更新 更多