带有工厂和模型虚拟属性的 Rspec 不起作用?

发布于 2024-10-20 15:07:57 字数 931 浏览 2 评论 0原文

我正在使用 Rspec 和工厂女孩来设置我的测试。我有一个用户工厂,然后我正在使用 rspec 进行测试。

在名为 GameEngine::Formulas 的模块中,我有一个虚拟属性(实际上 hp 已经是模型,它在这里被覆盖):

def hp
    ((self[:hp] * 5) * (self.level + 1)) if self.first_class == 'Fighter'
    ((self[:hp] * 4) * (self.level + 1)) if self.first_class == 'Ranger'
    ((self[:hp] * 2) * (self.level + 1)) if self.first_class == 'Magician'
end 

当我删除这个虚拟属性时,测试工作正常。但如果我把它留在这里,我就会明白:

 Failure/Error: let(:user) { Factory(:user) }
 ActiveRecord::RecordInvalid:
   Validation failed: Hp can't be blank

工厂:

Factory.define :user do |f|
    f.sequence(:username) { |n| "test#{n}" }
    f.password "1234567890"
    f.sequence(:email) { |n| "test#{n}@test.com" }
    f.first_class 'Ranger'
    f.hp 10000
    f.strength 100
    f.magic 100
    f.dexterity 100
    f.accuracy 10
    f.armor 20
    f.level 1
end

为什么会这样?

i'm using Rspec and factory girl to set my tests. I have a user factory and then i'm testing with rspec.

In a module named GameEngine::Formulas, i have a virtual attribute(actually hp is already i the model, it's overridden here) :

def hp
    ((self[:hp] * 5) * (self.level + 1)) if self.first_class == 'Fighter'
    ((self[:hp] * 4) * (self.level + 1)) if self.first_class == 'Ranger'
    ((self[:hp] * 2) * (self.level + 1)) if self.first_class == 'Magician'
end 

When i remove this virtual attrib, the test works fine. But if i leave it here, i get that :

 Failure/Error: let(:user) { Factory(:user) }
 ActiveRecord::RecordInvalid:
   Validation failed: Hp can't be blank

FACTORY :

Factory.define :user do |f|
    f.sequence(:username) { |n| "test#{n}" }
    f.password "1234567890"
    f.sequence(:email) { |n| "test#{n}@test.com" }
    f.first_class 'Ranger'
    f.hp 10000
    f.strength 100
    f.magic 100
    f.dexterity 100
    f.accuracy 10
    f.armor 20
    f.level 1
end

Why is that ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

遮了一弯 2024-10-27 15:07:57

原始代码中的问题是,除非 first_class == 'Magician',否则它会返回 nil。如果条件为 false,则带有尾随条件的语句将返回 nil,例如,

> 1 + 1 if true
# => 2

> 1 + 1 if false
# => nil

每次调用都会执行所有三个测试,因此前两个测试的结果会被后续测试的结果所掩盖。

您可以用 case 语句重写它:

  def hp
    case first_class
    when 'Fighter'
      ((self[:hp] * 5) * (level + 1))
    when 'Ranger'
      ((self[:hp] * 4) * (level + 1))
    when 'Magician'
      ((self[:hp] * 2) * (level + 1))
    end
  end

The problem in the original code is that it returns nil except when first_class == 'Magician'. A statement with a trailing conditional returns nil if the condition is false, e.g.

> 1 + 1 if true
# => 2

> 1 + 1 if false
# => nil

All three tests are performed for each invocation, so the results of the first two are masked by the subsequent one(s).

You could rewrite it with a case statement:

  def hp
    case first_class
    when 'Fighter'
      ((self[:hp] * 5) * (level + 1))
    when 'Ranger'
      ((self[:hp] * 4) * (level + 1))
    when 'Magician'
      ((self[:hp] * 2) * (level + 1))
    end
  end
荒岛晴空 2024-10-27 15:07:57

我通过将 if 结构更改为 if..elsif 解决了这个问题。

我猜想显式返回值然后再进行另一个 if 检查会弄乱事情。不确定为什么会出现这种情况,但当我这样做时它起作用了。

I resolved this by changing the if structure to if..elsif.

I guess that explicitly returning the value and then having another if check was messing the things. Not sure exactly why this is the case, but it worked when i did that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文