Ruby on rails 使用factory_girl设置模型测试的对象
我想测试下面的作用域,但不知道如何正确设置测试对象。我甚至不知道我是否应该在工厂中使用一些关联或使用let/local变量创建它们 task.rbRuby on rails 使用factory_girl设置模型测试的对象,ruby-on-rails,rspec,factory-bot,Ruby On Rails,Rspec,Factory Bot,我想测试下面的作用域,但不知道如何正确设置测试对象。我甚至不知道我是否应该在工厂中使用一些关联或使用let/local变量创建它们 task.rb belongs_to :assigner, class_name: "User" belongs_to :executor, class_name: "User" scope :completed, -> { where.not(completed_at: nil) } scope :uncompleted, -> { where(co
belongs_to :assigner, class_name: "User"
belongs_to :executor, class_name: "User"
scope :completed, -> { where.not(completed_at: nil) }
scope :uncompleted, -> { where(completed_at: nil) }
scope :alltasks, -> (u) { where('executor_id = ? OR assigner_id = ?', u.id, u.id) }
scope :between, -> (assigner_id, executor_id) do
where("(tasks.assigner_id = ? AND tasks.executor_id = ?) OR (tasks.assigner_id = ? AND tasks.executor_id = ?)", assigner_id, executor_id, executor_id, assigner_id)
end
工厂
factory :task do
content { Faker::Lorem.sentence }
deadline { Faker::Time.between(DateTime.now + 2, DateTime.now + 3) }
association :executor, factory: :user
association :assigner, factory: :user #I guess this is not right
end
factory :user do
sequence(:email) { |n| "example#{n}@gmail.com" }
password 'example0000'
password_confirmation 'example0000'
new_chat_notification { Faker::Number.between(0, 10) }
new_other_notification { Faker::Number.between(0, 10) }
end
任务_spec.rb
describe Task do
.....
describe "scopes" do
#I DON'T KNOW HOW TO SETUP THE TEST OBJECTS PROPERLY
let(:uncompleted_task) { create(:task) }
let(:completed_task) { create(:task, completed_at: DateTime.now - 2) }
let(:user) { create(:user)
let(:task_1) { create(:task, executor_id: user.id, assigner_id: (user.id + 1)) }
let(:task_2) { create(:task, assigner_id: user.id, executor_id: (user.id + 1) }
let(:task_3) { create(:task, assigner_id: user.id, executor_id: (user.id + 2) }
it "completed" do
expect(completed_task).to eq(Task.completed.first)
end
it "uncompleted" do
expect(uncompleted_task).to eq(Task.uncompleted.last)
end
it "alltasks" do
end
it "between" do
end
end
end
首先,我不喜欢在工厂里建立协会,原因如下:
范围划分为小范围
let
的用法,使用let定义的对象仅在测试用例中调用时创建。在原始规范中,由于未调用任何任务或用户,因此不会创建任何任务或用户。要执行所需操作,应在块之前使用
例如,我将创建以下工厂和规格:
工厂
factory :task do
content { Faker::Lorem.sentence }
deadline { Faker::Time.between(DateTime.now + 2, DateTime.now + 3) }
end
factory :user do
sequence(:email) { |n| "example#{n}@gmail.com" }
sequence(:password) { |n| "password#{n}" }
password_confirmation { password }
new_chat_notification { Faker::Number.between(0, 10) }
new_other_notification { Faker::Number.between(0, 10) }
end
规格
Noel Rappin的《Rails 4测试处方-构建健康的代码库》一书中有更多关于如何编写测试的细节和热门内容,如果您感兴趣,值得一读 首先,由于以下原因,我不喜欢在工厂建立协会:
如果工厂中存在关联,则每次创建/构建对象时,都会同时创建关联对象。这意味着即使您只是“构建”一个对象,也会触发许多数据库访问。使用的关联越多,运行测试所需的时间就越多
当您确实需要时,您应该在测试中设置关联。如果您在工厂中设置关联,这意味着给定when-then流程的“给定”部分在测试中隐藏。当测试失败时,发现哪里出了问题变得更加困难
要测试范围,您应该遵循以下最佳实践:
使您的作用域尽可能简单,测试复杂的作用域会更加困难。例如,如果需要,您应该将范围划分为小范围
使用最小对象来测试范围,因为我们需要在数据库中创建记录来测试范围。数据库访问减慢了测试速度,我们应该尽可能减少对象的创建。对于大多数情况,两个对象(正和负)应该足以测试一个简单的范围
顺便说一句,您可能会误解let
的用法,使用let定义的对象仅在测试用例中调用时创建。在原始规范中,由于未调用任何任务或用户,因此不会创建任何任务或用户。要执行所需操作,应在
块之前使用
例如,我将创建以下工厂和规格:
工厂
factory :task do
content { Faker::Lorem.sentence }
deadline { Faker::Time.between(DateTime.now + 2, DateTime.now + 3) }
end
factory :user do
sequence(:email) { |n| "example#{n}@gmail.com" }
sequence(:password) { |n| "password#{n}" }
password_confirmation { password }
new_chat_notification { Faker::Number.between(0, 10) }
new_other_notification { Faker::Number.between(0, 10) }
end
规格
Noel Rappin的《Rails 4测试处方-构建健康的代码库》一书中有更多关于如何编写测试的细节和热门内容,如果您感兴趣,值得一读 你看到的问题是什么?例如,当您尝试运行此代码时,您会收到什么错误消息?使用此代码时,什么都没有,但我从alltasks
中删除了此代码,因为PG用户已经存在问题。如您所见,对于alltasks
和between
我必须创建一些具有给定用户id的任务,以检查这些任务是否只返回匹配的任务。因此,我的问题是为这些方法设置适当的用户和任务对象。正如我提到的,我甚至不知道从什么方法开始。你看到的问题是什么?例如,当您尝试运行此代码时,您会收到什么错误消息?使用此代码时,什么都没有,但我从alltasks
中删除了此代码,因为PG用户已经存在问题。如您所见,对于alltasks
和between
我必须创建一些具有给定用户id的任务,以检查这些任务是否只返回匹配的任务。因此,我的问题是为这些方法设置适当的用户和任务对象。正如我所提到的,我甚至不知道该从什么方法开始。我已经阅读了使用RSpec的Rails日常测试和Rails 4测试处方的前半部分,但没有真正了解到let
的确切作用。你有一篇很好的文章,比较let+工厂+以前吗?你知道问题是所有的消息来源都有不同的说法。我不明白为什么我不能使用let
。我的意思是,我在let
定义中使用create
,这样一旦测试调用了特定的测试,对象就会持久化。至于您的示例,您将其用于用户而不是任务,我不明白为什么。你能更详细地阐述一下你的答案吗,或者指出一个关于let
的惊人来源吗?Thxlet
就像一个声明,let(:executor){create(:user)}
不会在数据库中创建任何用户记录,直到@uncompleted_task=create(:task,executor:executor,assigner:assigner)
被执行,也就是说,let(:executor)
只在使用executor
时创建用户记录(调用