Cucumber Ruby(Capybara)跨步骤共享实例变量问题:页面断言时@thing为nil报错
@thing为nil的NoMethodError问题 Hey there! Let's break down why you're hitting that undefined method 'name' for nil:NilClass error and fix it step by step.
1. 核心问题:步骤定义的语法错误
The biggest culprit here is the syntax in your step definitions—you've got an extra space between the keyword (Given/And/When/Then) and the quoted step string. This breaks Cucumber's step matching, meaning your @thing instance variable never gets initialized in the first place.
错误写法
Given ("I am a user") do @user = FactoryBot.create(:user) end And ("I own a thing") do @thing = FactoryBot.create(:thing, user: @user) end
正确写法
Remove the space between the keyword and the string (or skip the parentheses entirely, which is Cucumber's recommended style):
Given("I am a user") do @user = FactoryBot.create(:user) end And("I own a thing") do @thing = FactoryBot.create(:thing, user: @user) end # 或者更简洁的无括号写法 Given "I am a user" do @user = FactoryBot.create(:user) end And "I own a thing" do @thing = FactoryBot.create(:thing, user: @user) end
2. 修复页面路由的逻辑
Your attempt to use visit (page_path($thing)) was off—global variables like $thing aren't the right approach here, and you're probably using the wrong route helper.
If you're trying to visit the detail page for your thing, use Rails' standard resource route helper (thing_path) instead of page_path:
When("I visit the page") do # 访问物品详情页 visit thing_path(@thing) # 如果是用户的物品列表页,用这个: # visit user_things_path(@user) end
Double-check your config/routes.rb to confirm the correct route helper for your page.
3. 验证变量共享与步骤执行
Cucumber shares instance variables (@user, @thing) across steps as long as the steps are matched correctly. To debug, add simple print statements to confirm variables are being created:
Given("I am a user") do @user = FactoryBot.create(:user) puts "Created user ID: #{@user.id}" # 调试用,确认用户创建成功 end And("I own a thing") do @thing = FactoryBot.create(:thing, user: @user) puts "Created thing name: #{@thing.name}" # 调试用,确认物品创建成功 end Then("I can see my thing") do puts "Thing name in final step: #{@thing&.name}" # 调试用,看变量是否存在 expect(page).to have_text(@thing.name) end
额外优化:更清晰的步骤设计
For better maintainability, make your feature steps more explicit and use parameterization to reuse code:
Feature文件优化
Feature: View Owned Things Given I am a registered user And I have created a thing named "My Custom Thing" When I visit my thing's detail page Then I should see the text "My Custom Thing"
对应的步骤定义
Given("I am a registered user") do @user = FactoryBot.create(:user) end Given("I have created a thing named {string}") do |thing_name| @thing = FactoryBot.create(:thing, user: @user, name: thing_name) end When("I visit my thing's detail page") do visit thing_path(@thing) end Then("I should see the text {string}") do |expected_text| expect(page).to have_text(expected_text) end
内容的提问来源于stack exchange,提问作者cinameng

