问题描述
我正在尝试在 Michael 中进行第 8.5 章的练习 2Hartl 的 Ruby on Rails 教程.练习如下:
I'm trying to do Exercise 2 of Chapter 8.5 in Michael Hartl's Ruby on Rails Tutorial. The exercise is as follows:
按照第 8.3.3 节中的示例,通过用户和身份验证请求规范(即当前在 spec/requests 目录中的文件)并在 spec/support/utilities.rb 中定义实用程序函数以将测试与实施.额外的功劳:将支持代码组织到单独的文件和模块中,并通过在规范帮助文件中正确包含模块来使一切正常工作.
Following the example in Section 8.3.3, go through the user and authentication request specs (i.e., the files currently in the spec/requests directory) and define utility functions in spec/support/utilities.rb to decouple the tests from the implementation. Extra credit: Organize the support code into separate files and modules, and get everything to work by including the modules properly in the spec helper file.
示例 8.3.3:utility.rb
Example 8.3.3: utilities.rb
include ApplicationHelper
def valid_signin(user)
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button "Sign in"
end
RSpec::Matchers.define :have_error_message do |message|
match do |page|
page.should have_selector('div.alert.alert-error', text: message)
end
end
定义的 valid_signin(user)
函数用于以下 authentication_pages_spec.rb
块中,并且工作正常.
The defined valid_signin(user)
function is used in the following block of authentication_pages_spec.rb
and works fine.
describe "with valid information" do
let(:user){FactoryGirl.create(:user)}
before { valid_signin(user) }
it { should have_selector('title', text: user.name) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Sign out', href: signout_path) }
it { should_not have_link('Sign in', href: signin_path) }
describe "followed by signout" do
before { click_link "Sign out" }
it { should have_link('Sign in') }
end
end
因此,在此示例中,我开始创建自己的名为 valid_signup(user)
:
So with this example I set about to create my own named valid_signup(user)
:
def valid_signup(user)
fill_in "Name", with: user.name
fill_in "Email", with: user.email
fill_in "Password", with: user.password
fill_in "Confirmation", with: user.password_confirmation
end
我在 user_pages_spec.rb
中像这样使用这个块:
I'm using this block in user_pages_spec.rb
like this:
describe "with valid information" do
let(:user){FactoryGirl.create(:user)}
before { valid_signup(user) }
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after saving the user" do
before { click_button submit }
let(:user) { User.find_by_email(user.email) }
it { should have_selector('title', text: user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
it { should have_link('Sign out') }
end
end
它不起作用.Spork/Guard 报告这些错误:
It doesn't work. Spork/Guard reports these errors:
Failures:
1) UserPages signup with valid information should create a user
Failure/Error: expect { click_button submit }.to change(User, :count).by(1)
count should have been changed by 1, but was changed by 0
# ./spec/requests/user_pages_spec.rb:46:in `block (4 levels) in '
2) UserPages signup with valid information after saving the user
Failure/Error: before { valid_signup(user) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/support/utilities.rb:10:in `valid_signup'
# ./spec/requests/user_pages_spec.rb:43:in `block (4 levels) in '
3) UserPages signup with valid information after saving the user
Failure/Error: before { valid_signup(user) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/support/utilities.rb:10:in `valid_signup'
# ./spec/requests/user_pages_spec.rb:43:in `block (4 levels) in '
4) UserPages signup with valid information after saving the user
Failure/Error: before { valid_signup(user) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/support/utilities.rb:10:in `valid_signup'
# ./spec/requests/user_pages_spec.rb:43:in `block (4 levels) in '
错误似乎表明 utilities.rb
中的 valid_signup(user)
函数中的 user.name 未定义,但我看不出任何原因为什么.我已经多次重新启动 Guard,并执行了 rake db:test:prepare
以确保测试数据库(使用 postgresql)是有序的.
The errors seem to suggest the user.name in my valid_signup(user)
function in utilities.rb
isn't defined, but I don't see any reason why. I've restarted Guard several times, and did a rake db:test:prepare
to make sure the testing db (using postgresql) was in order.
为了完整性,这是我的 factories.rb
:
Here's my factories.rb
for completeness:
FactoryGirl.define do
factory :user do
name "Example User"
email "user@example.com"
password "foobar"
password_confirmation "foobar"
end
end
在我继续尝试分离更多测试套件之前,我非常想解决这个错误,更重要的是,了解它的原因.
Before I continue to try and decouple more of the testing suite I'd very much like to solve this error and, more importantly, understand the reason for it.
编辑
我已经尝试了你的提示,并在 user_pages_spec.rb
中编辑了函数如下:
I've tried your tips, and edited the function in user_pages_spec.rb
as follows:
describe "with valid information" do
before { valid_signup(user) }
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after saving the user" do
before { click_button submit }
let(:user) { User.find_by_email('user@example.com') }
it { should have_selector('title', text: user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
it { should have_link('Sign out') }
end
end
自从我从函数中删除了 let(:user){FactoryGirl.create(:user)}
我猜在函数中不再创建用户所以我需要定义 valid_signup(user)
例如 valid_signup
的 user
变量不再由 FactoryGirl 填充:
Since I removed let(:user){FactoryGirl.create(:user)}
from the function I guessed there was no longer a user created in the function so I needed to define valid_signup(user)
as such as the user
variable for valid_signup
was no longer being filled by FactoryGirl:
def valid_signup(user)
fill_in "Name", with: "Example User"
fill_in "Email", with: "user@example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmation", with: "foobar"
end
这不起作用,并给了我以下错误:
This didn't work and gave me the following errors:
Failures:
1) 使用有效信息注册 UserPages 应创建一个用户失败/错误:在 { valid_signup(user) } 之前名称错误:未定义的局部变量或方法
user' for #<RSpec::Core::ExampleGroup::Nested_5::Nested_3::Nested_2:0x007fdafc5088c0># ./spec/requests/user_pages_spec.rb:42:in
block (4 levels) in '
1) UserPages signup with valid information should create a user Failure/Error: before { valid_signup(user) } NameError: undefined local variable or method
user' for #<RSpec::Core::ExampleGroup::Nested_5::Nested_3::Nested_2:0x007fdafc5088c0> # ./spec/requests/user_pages_spec.rb:42:in
block (4 levels) in '
2) 保存用户后使用有效信息注册 UserPages失败/错误:它 { should have_selector('title', text: user.name) }无方法错误:未定义的方法
name' for nil:NilClass# ./spec/requests/user_pages_spec.rb:52:in
block (5 levels) in '
2) UserPages signup with valid information after saving the user Failure/Error: it { should have_selector('title', text: user.name) } NoMethodError: undefined method
name' for nil:NilClass # ./spec/requests/user_pages_spec.rb:52:in
block (5 levels) in '
我还尝试使用 valid_signup(user)
运行测试,就像我以前使用的方式(使用 user.name, user.email, user.password, user.password_confirmation
,它也不起作用,有错误:
I also tried running the test with valid_signup(user)
the way I used to have it before (with user.name, user.email, user.password, user.password_confirmation
, which didn't work either, with errors:
Failures:
1) UserPages signup with valid information should create a user
Failure/Error: before { valid_signup(user) }
NameError:
undefined local variable or method `user' for #
# ./spec/requests/user_pages_spec.rb:42:in `block (4 levels) in '
2) UserPages signup with valid information after saving the user
Failure/Error: it { should have_selector('title', text: user.name) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/requests/user_pages_spec.rb:52:in `block (5 levels) in '
接下来我尝试运行它而不在 user_pages_spec.rb
中传递变量: before { valid_signup() }
并且在 utilities.rb 的函数中没有变量:
Next I tried running it without passing variables in
user_pages_spec.rb
: before { valid_signup() }
and without a variable in the function in utilities.rb
:
def valid_signup()
fill_in "Name", with: "Example User"
fill_in "Email", with: "user@example.com"
fill_in "Password", with: "foobar"
fill_in "Confirmation", with: "foobar"
end
返回:
Failures:
1) UserPages signup with valid information should create a user
Failure/Error: before { valid_signup(user) }
NameError:
undefined local variable or method `user' for #
# ./spec/requests/user_pages_spec.rb:42:in `block (4 levels) in '
2) UserPages signup with valid information after saving the user
Failure/Error: it { should have_selector('title', text: user.name) }
NoMethodError:
undefined method `name' for nil:NilClass
# ./spec/requests/user_pages_spec.rb:52:in `block (5 levels) in '
仍然没有接近答案.我可能忽略了一些简单的事情.虽然不知道是什么.不过,我第一次做错了:我只是认为 FactoryGirl 是一种创建变量的方法,但我不知道它实际上对我的测试数据库做了什么.
Still no closer to the answer. I might be overlooking something simple. No clue what though. I got what I first did wrong though: I just thought FactoryGirl was a way to create variables, and I didn't know it actually did something to my test database.
推荐答案
我将尝试解释您的原始测试中发生了什么(我发现它比编辑后的版本更容易修复):
I will try to explain what is going on in your original test (which I find easier to fix than the edited version):
describe "with valid information" do
let(:user) {FactoryGirl.build(:user)} # FactoryGirl.create will save the instance, you should be using build instead
before { valid_signup(user) }
it "should create a user" do
expect { click_button submit }.to change(User, :count).by(1)
end
describe "after saving the user" do
before { click_button submit }
# let(:user) { User.find_by_email(user.email) } # this is not needed any more
it { should have_selector('title', text: user.name) }
it { should have_selector('div.alert.alert-success', text: 'Welcome') }
it { should have_link('Sign out') }
end
end
有关 FactoryGirl 使用的更多信息:https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#using-factories
More info on FactoryGirl usage: https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#using-factories
这篇关于Rails 教程:RSpec 测试解耦的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!