我的rails应用程序中有一个方法,它执行一些复杂的查询并返回数据。
我有其他方法可以使用特定的方法对第一个返回的数据进行建模。
我需要为其他方法编写RSpec测试...我需要传递第一个方法的结果(因为执行取决于这个数据)
如何模拟数据库查询的响应,以便在测试我的其他方法时用作输入,而无需创建所有相关记录并调用第一种返回所需数据的方法?
首先查询方法:
def agents_tasks_performed_this_week_or_assigned(kind = 1)
condition = "..."
values = {...}
User.find(officer_id).supervised_users.active.joins(tasks: :ticket_subject)
.where(condition, values)
.select("users.id as agent_id, concat(users.first_name, ' ', users.last_name) as agent_name, date(tasks.completed_at) as completed_at, tasks.status, tasks.assigned_at")
end
测试方法:
def group_by_kind_and_date(supervisor_id = officer_id, tasks = []) # tasks is a result of the above method.
district_tasks = {}
tasks.each do |task|
unless district_tasks[task.agent_id.to_s]
district_tasks[task.agent_id] = new_rider_task_hash # this is a new hash of attributes
district_tasks[task.agent_id][:id] = task.agent_id
end
if district_tasks[task.agent_id][:name].nil?
district_tasks[task.agent_id][:name] = task.agent_name
end
...
district_tasks.values.sort_by{|item| item[:name].downcase }
end
RSpec测试:
require 'spec_helper'
describe <Module_name> do
let(:class_instance) { (Class.new {
include <Module_name>
}).new }
describe "#group_by_kind_and_date" do
it "should not include officers more than once in the response" do
returned_ids = class_instance.group_by_kind_and_date(@supervisor.id, <...need to pass in tasks mock here...>).map{ |d| d[:id]}
expect(returned_ids - returned_ids.uniq).to be_empty
end
end
end
所以......我需要获得一些类似于具有所有返回属性的模拟对象。
例如:如果返回值为tasks
,则模拟任务将具有以下属性:
task.agent_id, task.agent_name, task.completed_at, task.status and task.assigned_at
请注意。 Task实例没有以上所有属性......由于查询中返回了
.select
个值,因此这些属性可用。
感谢所有人的贡献。
答案 0 :(得分:2)
我的第一印象是你的方法很长,可能需要分成更小的方法。尝试使您的方法长度不超过3-4行。如果它更大 - 然后分成其他方法。例如,“tasks.each do”中的所有内容应该是一种方法(将单个任务和“区域任务”作为参数传递并返回“district_tasks”的更新版本)。同时将order-by部分取出另一个方法,将“district_tasks”作为arg并传递出有序集。
然后你没有更少的测试 - 你可以测试第一个(数据争用)方法接受一个任务并准备它。然后,您可以独立于数据争用方法测试排序方法。然后你可以测试整个方法为每个任务运行一次该方法,然后调用排序方法......
但是对于你的具体问题......你可以设置一个让双打,例如
let(:tasks) { [
double(:agent_id => '007', :agent_name => "Bond", :completed_at => 1.day.ago, :status => 'great', :assigned_at => 1.day.ago),
double(:agent_id => '99', :agent_name => "99", :completed_at => 2.days.ago, :status => 'in the cold', :assigned_at => 1.day.ago)
] }
然后将其用作第二个参数。
使用double,您可以传递一个键/值的哈希值,它将表示双重响应的“方法”以及尝试该方法时产生的值。
例如上面的任务示例将如下响应:
tasks[0].agent_id # => '007'
如果你需要添加不同的方法,同样只需将键/值添加到你需要的哈希中,你就可以了:)