【发布时间】:2012-07-05 03:52:18
【问题描述】:
我该怎么做:
it { should have_constant(:FIXED_LIST) }
在我的模型中(活动记录)我有FIXED_LIST = 'A String'
它不是 db 属性或方法,我无法使用 responds_to 或 has_attribute 对其进行测试(它们失败了)。我可以用什么来检查它。 - 顺便说一句,我已经安装了 shoulda-matchers。
【问题讨论】:
我该怎么做:
it { should have_constant(:FIXED_LIST) }
在我的模型中(活动记录)我有FIXED_LIST = 'A String'
它不是 db 属性或方法,我无法使用 responds_to 或 has_attribute 对其进行测试(它们失败了)。我可以用什么来检查它。 - 顺便说一句,我已经安装了 shoulda-matchers。
【问题讨论】:
根据 David Chelimsky 的回答,我可以通过稍微修改他的代码来实现这一点。
您可以在文件 spec/support/utilities.rb(或 spec/support 中的其他文件)中放置:
RSpec::Matchers.define :have_constant do |const|
match do |owner|
owner.const_defined?(const)
end
end
注意使用“RSpec::Matchers.define”而不是“matchers”
这允许测试规范中的常量,例如:
it "should have a fixed list constant" do
YourModel.should have_constant(:FIXED_LIST)
end
注意使用“have_constant”而不是“have_const”
【讨论】:
expect(YourModel).to have_constant(: FIXED_LIST)
读起来有点傻,但是:
describe MyClass do
it { should be_const_defined(:VERSION) }
end
原因是 Rspec 为以be_ 和have_ 开头的方法提供了“神奇”匹配器。例如,it { should have_green_pants } 会断言subject 上的has_green_pants? 方法返回true。
以同样的方式,it { should be_happy } 等示例将断言 subject 上的 happy? 方法返回 true。
因此,示例it { should be_const_defined(:VERSION) } 断言const_defined?(:VERSION) 返回true。
【讨论】:
NoMethodError ... undefined method const_defined?'` 错误告终。
it { subject.class.should be_const_defined(:MY_CONST) }。问题可能是由于它检查 subject 而不是 Class。
describe你的班级(不带引号),这应该按照 rspec 3.4 的规定工作。
如果你想说have_constant,你可以为它定义一个自定义匹配器:
matcher :have_constant do |const|
match do |owner|
owner.const_defined?(const)
end
end
MyClass.should have_const(:CONST)
如果您尝试使用单行语法,则需要确保主题是一个类(不是实例)或在匹配器中检查它:
matcher :have_constant do |const|
match do |owner|
(owner.is_a?(Class) ? owner : owner.class).const_defined?(const)
end
end
有关自定义匹配器的更多信息,请参阅http://rubydoc.info/gems/rspec-expectations/RSpec/Matchers。
HTH, 大卫
【讨论】:
undefined method matcher' for main:Object (NoMethodError)`
另一个简单地确保定义常量的选项——不用担心它是用什么定义的:
it 'has a WHATEVER constant' do
expect(SomeClass::WHATEVER).not_to be_nil
end
【讨论】:
对尝试测试已定义常量的任何人的警告:如果您的代码在定义类时引用未定义的常量,那么您的规范将在测试之前崩溃。
这会让你相信
expect { FOO }.to_not raise_error
未能捕捉到 NameError,因为你会得到一个很大的堆栈跟踪,而不是一个很好的“预计不会引发错误,但引发了 NameError”。
在巨大的堆栈跟踪中,很难注意到您的测试实际上在第 1 行崩溃:请求“spec/spec_helper”,因为您的整个应用程序在进入实际测试之前无法加载。
如果您有动态定义的常量,例如由 ActiveHash::Enum 完成,然后您在另一个常量的定义中使用它们,就会发生这种情况。不要费心测试它们是否存在,如果其中一个未定义,您应用中的每个规范都会崩溃。
【讨论】:
你可以使用
defined? YOUR_MODEL::FIXED_LIST
【讨论】:
it { should defined?(:EMPTY_TABLE) },但得到了undefined method matches?对于“表达式”:字符串`
should defined?(MODEL_NAME::EMPTY_TABLE) 呢?
在 RSpec 2 中,我能够让它在一行中工作,如下所示:
it { subject.class.should be_const_defined(:MY_CONST) }
也就是说,检查类,而不是实例。
【讨论】:
在我的模型中
class Role < ActiveRecord::Base
ROLE_ADMIN = "Administrador"
end
在我的 rspec 中
RSpec.describe Role, type: :model do
let(:fake_class) { Class.new }
describe "set constants" do
before { stub_const("#{described_class}", fake_class) }
it { expect(described_class::ROLE_ADMIN).to eq("Administrador") }
end
end
【讨论】: