我已经阅读了rspec docs,并搜索了许多其他地方,但是我很难理解Rspec的let和let!之间的区别
我读到过let只有在需要时才会被初始化,并且它的值只在每个示例中被缓存。我还读到过let!强制变量立即存在,并强制调用每个示例。我猜因为我是新手,所以我很难理解这与下面的例子有什么关系。为什么需要用let!设置:m1来断言页面上存在m1.content,而可以用let设置:user来断言页面包含text: user.name
subject { page }
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
let!(:m1) { FactoryGirl.create(:micropost, user: user, content: "Foo") }
let!(:m2) { FactoryGirl.create(:micropost, user: user, content: "Bar") }
before { visit user_path(user) }
it { should have_selector('h1', text: user.name) }
it { should have_selector('title', text: user.name) }
describe "microposts" do
it { should have_content(m1.content) }
it { should have_content(m2.content) }
it { should have_content(user.microposts.count) }
end
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_success_message('Welcome') }
it { should have_link('Sign out') }
end发布于 2013-07-01 23:13:43
因为之前的代码块调用的是visit user_path(user),所以用户值在那里被初始化,RSpec将访问该页面。如果:m1 :m2没有使用let!,那么访问将不会产生任何内容制作
it { should have_content(m1.content) }
it { should have_content(m2.content) }失败,因为它希望在用户访问页面之前创建微帖子。let!允许在调用之前代码块之前创建微帖子,并且当测试访问页面时,微帖子应该已经创建。
另一种编写相同测试并使其通过的方法是执行以下操作:
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
let(:m1) { FactoryGirl.create(:micropost, user: user, content: "Foo") }
let(:m2) { FactoryGirl.create(:micropost, user: user, content: "Bar") }
before do
m1
m2
visit user_path(user)
end在visit user_path(user)之前调用变量m1和m2会导致在访问页面之前对它们进行初始化,并导致测试通过。
UPDATE这个小例子更有意义:
在本例中,我们调用get_all_posts,它只返回一个帖子数组。注意,我们在断言之前和it块执行之前调用了该方法。因为post在断言执行之前不会被调用。
def get_all_posts
Post.all
end
let(:post) { create(:post) }
before { @response = get_all_posts }
it 'gets all posts' do
@response.should include(post)
end通过使用let!,只要RSpec看到该方法(在before块之前),就会创建post,并在Post列表中返回post
同样,另一种做同样事情的方法是在调用方法之前先在之前的块中调用变量名
before do
post
@response = get_all_posts
end因为这将确保在调用方法本身之前调用let(:post)块,从而创建Post,以便在Post.all调用中返回它
发布于 2014-01-11 18:42:59
区分的关键是rspec如何执行这些步骤。
再看一遍代码:
let(:user) { FactoryGirl.create(:user) }
let!(:m1) { FactoryGirl.create(:micropost, user: user, content: "Foo") }
let!(:m2) { FactoryGirl.create(:micropost, user: user, content: "Bar") }
before { visit user_path(user) }如果我们使用let而不是let!,此时不会创建m1和m2。然后Rspec访问并加载页面,但显然页面上既没有m1也没有m2。
因此,现在如果我们调用m1和m2,它们将在内存中创建。但是已经太晚了,因为页面将不会再次加载,除非我们有意这样做。因此,页面上的任何UI测试都将导致失败。
https://stackoverflow.com/questions/17407733
复制相似问题