我正在用Capybara测试产品的创建,即我正在用自动测试填写表格。该产品属于某些型号,例如,属于房屋。
我有两个工厂文件来创建这两个模型,即产品和房屋。在表格中,用户应从选择(下拉)中选择房屋。我设法做到了,但是解决方案感觉不干净:
(我正在功能测试中创建房屋实例,因为我需要在产品的表单中选择房屋。该房屋属于其他模型)
require 'rails_helper'
require 'pry'
RSpec.describe 'Add a product features' do
context "Create new product from add a product menu" do
let(:user) { create(:user) }
let!(:home) { create(:home, name: "My Place", user: user) }
before(:each) do
# home.name = "My place"
# home.save
end
before(:each) do
# binding.pry
login_as(user, :scope => :user)
visit menu_add_product_path
click_link("Take a picture")
expect(current_path).to eql('/products/new')
binding.pry
within('form') do
attach_file('product_taken_photos_attributes_0_taken_pic', File.absolute_path('./app/assets/images/macbook1.jpg'))
fill_in 'Brand', with: "Apple"
fill_in 'Product type', with: "Smartphone"
fill_in 'Price of purchase', with: 800.3
fill_in 'Date of purchase', with: "2017-05-03"
select("My place", :from => 'product_home_id')
end
end
it 'should be successful' do
binding.pry
within('form') do
fill_in 'Model', with: "Iphone 6"
end
click_button('Create Product')
binding.pry
expect(current_path).to eql(product_path(Product.last))
expect(page).to have_content 'Iphone 6'
end
# it 'should not be successful' do
# click_button('Create Product')
# expect(current_path).to eql('/products') # the post products actually!
# expect(page).to have_content(/Model can\'t be blank/)
# end
end
end
工厂:
home.rb
FactoryBot.define do
factory :home do
sequence(:name) { |n| "My Home#{n}" }
address 'c/ Viladomat n200 50 1a'
insurer
house_type
user
end
end
product.rb
FactoryBot.define do
factory :product do
model 'macbook pro'
form_brand 'apple'
form_product_type 'laptop'
price_of_purchase 1200
date_of_purchase Date.new(2017,06,06)
end
end
user.rb
FactoryBot.define do
factory :user do
sequence(:email) { |n| "myemail#{n}@mail.com" }
password 123456
end
end
house_type.rb
FactoryBot.define do
factory :house_type do
name 'Flat'
end
end
如果我使用let!操作员为所有测试创建一个主页,测试失败:
let!(:home) { create(:home, name: "My Place", user: user) }
控制台日志:
Capybara::ElementNotFound:
Unable to find visible option "My place" within #<Capybara::Node::Element tag="select" path="/html/body/div[2]/form/div[4]/div/div[2]/select">
但是,如果我手动创建房屋,那么在每次测试之前,它都会起作用
let(:home) { create(:home, name: "My Place", user: user) }
before(:each) do
home.name = "My place"
home.save
end
为什么放手!不工作吗?如果我在测试中放了binding.pry,则在两种情况下,我的数据库中都创建了主页。
答案 0 :(得分:1)
您应该将工厂配置为自动创建所需的默认关联,以便可以在测试中创建所需的实例,而不必创建所有其他非专用记录。您的家庭工厂应该看起来像
FactoryBot.define do
factory :home do
sequence(:name) { |n| "Home#{n}" }
address { 'c/ Viladomat n200 50 1a' } # You might want to define this to use a sequence too so it's unique when you create multiples
insurer
house_type
user
end
end
这样,您便可以通过调用Home
来创建有效的create(:home)
实例。如果要自定义任何关联/参数,可以将它们传递给工厂的create / build方法。所以在您的示例中,它将变成
let(:home) { create(:home, name: 'My place') }
如果您还想手动创建user
对象,以便可以调用login(user...)
而不用访问像login(home.user...)
这样的自动生成的用户,则可以这样做
let(:user) { create(:user) }
let!(:home) { create(:home, name: 'My place', user: user }
请注意,let!
而非home
使用let
。这是因为let
的计算是延迟的,因此直到您在测试中首次调用home
时,才会真正构建该实例-因为调用login_as(user...
时不会调用{{ 1}}在测试中,您需要改用home
,以便在运行测试之前创建对象。您可能还希望在用户工厂的let!
之类的东西中使用FactoryBot序列,以便可以在测试中创建多个用户。
此外,您正在调用email
,由于expect(current_path).to eql('/new_from_camera')
匹配器没有内置的等待行为,这将导致不稳定的测试。相反,您应该始终喜欢Capybara提供的匹配器,这意味着应调用eql
。
答案 1 :(得分:0)
我认为您可以直接在home
工厂中添加关联:
let(:insurer) { create(:insurer) }
let(:house_type) { create(:house_type) }
let(:user) { create(:user) }
let(:home) { create(:home, name: "My place", insurer: insurer, house_type: house_type, user: user) }