Cucumber场景下如何以人性化可读方式填写嵌套属性表格内的表单字段
完全理解你的痛点!用item_supplier[supplier_item_prices_attributes][0][price]这种充满技术细节的字段名写Cucumber步骤,不仅可读性差,后续表单结构或属性名一变,所有相关场景都得跟着改,维护起来太折腾了。
下面给你几个实用方案,让你的Cucumber步骤回归“人话”风格:
方案1:自定义Cucumber步骤,按商品名称定位价格字段
这是最推荐的方案——把技术细节封装到步骤定义里,场景里只用写业务层面的描述。比如你可以把原来的技术步骤替换成:
And I set the price for item "Widget A" to "1,23"
然后在你的Cucumber步骤定义文件(比如features/step_definitions/form_steps.rb)里实现这个步骤:
When(/^I set the price for item "([^"]*)" to "([^"]*)"$/) do |item_name, target_price| # 找到包含目标商品名称的表格行 within(:xpath, "//tr[contains(., '#{item_name}')]") do # 在该行内找到价格输入框并填充 fill_in 'price', with: target_price, match: :first end end
为什么这样可行?
你的ERB模板里,每个表格行都会显示对应商品的名称(<%= ff.object.item.name %>),用XPath定位包含该名称的<tr>,再在该行内找价格输入框,完全符合用户操作表单的真实逻辑——先找到商品对应的行,再填写价格。
如果觉得XPath不够优雅,也可以给表格行加个自定义属性让定位更精准:
在ERB的<tr>标签里添加:
<tr data-item-name="<%= ff.object.item.name %>">
然后步骤定义改成用CSS选择器:
When(/^I set the price for item "([^"]*)" to "([^"]*)"$/) do |item_name, target_price| within("tr[data-item-name='#{item_name}']") do find('input[name$="[price]"]').set(target_price) end end
方案2:给价格输入框添加友好的定位标识
如果不想依赖商品名称的文本定位,也可以给价格输入框加个自定义的data-*属性,让Cucumber能直接定位到它:
修改ERB里的价格输入框代码:
<%= ff.text_field :price, label: false, data: { item_name: ff.object.item.name } %>
然后步骤定义可以直接通过这个data-item-name属性定位:
When(/^I set the price for item "([^"]*)" to "([^"]*)"$/) do |item_name, target_price| find("input[data-item-name='#{item_name}']").set(target_price) end
这种方式定位更直接,也避免了XPath可能出现的文本匹配问题。
方案3:按商品顺序的人性化步骤(备选)
如果你的商品列表顺序是固定的,也可以用类似“第一个商品”“第二个商品”的描述,比如:
And I set the price for the first item to "1,23"
步骤定义里用索引定位:
When(/^I set the price for the (\w+) item to "([^"]*)"$/) do |position, target_price| index = case position when 'first' then 0 when 'second' then 1 # 可以继续扩展更多位置描述,比如third、fourth等 end fill_in "item_supplier[supplier_item_prices_attributes][#{index}][price]", with: target_price end
不过这个方案的灵活性不如按商品名称定位,更适合商品顺序固定的场景。
核心思路总结
Cucumber的核心优势就是用自然语言描述业务场景,所以一定要把技术细节封装在步骤定义里,让.feature文件保持纯粹的业务可读性。不管用哪种方案,最终的目标都是让你的场景变成:
When I fill in "Name des Lieferanten" with "any_name" And I fill in "Straße & Hausnummer" with "SBS 62" And I fill in "Postleitzahl" with "12345" And I fill in "Stadt" with "Bonn" And I set the price for item "Widget A" to "1,23"
这样不仅非技术人员能看懂,后续表单结构变化时,只需要修改对应的步骤定义,不用动所有场景文件。
内容来源于stack exchange

