Ruby on rails 指定显式';受试者';s
我正在使用RubyonRails3.0.9和RSpect2。我正试图以以下方式重构一些spec文件(以便用更少的代码类似Ruby on rails 指定显式';受试者';s,ruby-on-rails,ruby,ruby-on-rails-3,rspec,rspec2,Ruby On Rails,Ruby,Ruby On Rails 3,Rspec,Rspec2,我正在使用RubyonRails3.0.9和RSpect2。我正试图以以下方式重构一些spec文件(以便用更少的代码类似Userclass对象属性值进行测试): 但是,如果运行上述测试,则会出现以下错误: Failure/Error: it "should be whatever" do NoMethodError: undefined method `it' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_2::Nested
User
class对象属性值进行测试):
但是,如果运行上述测试,则会出现以下错误:
Failure/Error: it "should be whatever" do
NoMethodError:
undefined method `it' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_2::Nested_2:0x00000106ccee60>
undefined local variable or method `user1' for #<Class:0x00000105310758> (NameError)
问题是一个规范嵌套在另一个规范中。您需要将
it“foreach user”
替换为context“foreach user”
编辑以添加:经过一些调查后,使用let
设置的帮助程序似乎仅在它“应该…”
块中可用,而不在周围的上下文中。我建议你尝试找到一个不同的结构性解决方案。最佳解决方案取决于您实际尝试测试的内容。我猜您要做的是确保在删除任何必需属性时用户无效。在这种情况下,我所做的是这样的:
describe User do
let(:user_attributes){ Factory.attributes_for(:user) }
# Testing missing values aren't valid
[:name, :email, :phone].each do |required_attribute|
it "should not be valid without #{required_attribute}" do
User.new(user_attributes.except(required_attribute)).should_not be_valid
end
end
# Testing invalid values aren't valid
[[:email, 'not_an_email'], [:phone, 'not a phone']].each do |(attribute, value)|
it "should not be valid with bad value for #{attribute}" do
User.new(user_attributes.update(attribute => value)).should_not be_valid
end
end
end
context "for all users" do
[:user1, :user2, :user3].each do |user|
it "does something" do
send(user).valid?.should be_true
end
end
end
如果您正在做的事情需要在您创建的实例中有更复杂的差异,那么可能没有一种干净的方法可以通过迭代来完成。我不认为DRY在测试中像在代码的其他部分一样重要。对于这三种用户类型,有三种不同的上下文,并在每种上下文中进行有效性测试,没有什么错
describe User do
context "with user1" do
subject{ Factory(:user, :users_attribute_a => 'invalid_value') }
it{ should_not be_valid }
end
context "with user2" do
subject{ Factory(:user, :users_attribute_b => 'invalid_value') }
it{ should_not be_valid }
end
context "with user3" do
subject{ Factory(:user, :users_attribute_c => 'invalid_value') }
it{ should_not be_valid }
end
end
问题是,设置为“let”的助手不存在于示例上下文之外 您试图做的事情可以通过以下方式实现:
it "does something with all users" do
[user1, user2, user3] do |user|
user.valid?.should be_true
end
end
两种情况都不同
另一种可能有效的方法(没有尝试过)是这样的:
describe User do
let(:user_attributes){ Factory.attributes_for(:user) }
# Testing missing values aren't valid
[:name, :email, :phone].each do |required_attribute|
it "should not be valid without #{required_attribute}" do
User.new(user_attributes.except(required_attribute)).should_not be_valid
end
end
# Testing invalid values aren't valid
[[:email, 'not_an_email'], [:phone, 'not a phone']].each do |(attribute, value)|
it "should not be valid with bad value for #{attribute}" do
User.new(user_attributes.update(attribute => value)).should_not be_valid
end
end
end
context "for all users" do
[:user1, :user2, :user3].each do |user|
it "does something" do
send(user).valid?.should be_true
end
end
end
你在混合和匹配各种rspec材料。这是你的东西,修正了:
describe User do
let(:user1) { Factory(:user, :users_attribute_a => 'invalid_value') }
let(:user2) { Factory(:user, :users_attribute_b => 'invalid_value') }
let(:user3) { Factory(:user, :users_attribute_c => 'invalid_value') }
it "should not be valid" do
[ user1, user2, user3 ].each do |user|
user.should_not be_valid
end
end
end
我会这样做:
describe User do
subject{Factory.build(:user)}
it "should not be valid with invalid users_attribute_a" do
subject.users_attribute_a = "invalid_value"
subject.should_not be_valid
end
it "should not be valid with invalid users_attribute_b" do
subject.users_attribute_b = "invalid_value"
subject.should_not be_valid
end
end
- 如果你想有“上下文”,那么很酷,但是你不能在上下文之前有变量
- 如果你想有一个规范,那么就有一个规范,但你不能用“it”语句
describe User do
it "should not be valid with other attributes" do
{:users_attribute_a => 'invalid_value', :users_attribute_b => 'invalid_value', :users_attribute_c => 'invalid_value'}.each do |key, value|
Factory.build(:user, key => value).should_not be_valid
end
end
end
这应该行得通。注意上下文是如何编写的,它将使测试的输出更加清晰。这样写意味着(对我来说)你应该分别对每个属性进行测试,但这是你的选择:
describe User do
let!(:users) {
[:users_attribute_a, :users_attribute_b, :users_attribute_c].map do |a|
Factory(:user, => 'invalid_value')
end
}
context "Given a user" do
context "With an invalid value" do
subject { users }
it { subject.all?{|user| should_not be_valid }
end
end
end
仅供参考,
subject
的使用在这里是一种误导。您从未实际使用示例中设置的主题。在第二个块中重构代码以减少代码编写量的方法是什么?您可以使用let
将变量过滤到上下文中