【发布时间】:2016-05-26 15:20:17
【问题描述】:
我的 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从查询返回值。
感谢大家的所有贡献。
【问题讨论】:
-
听起来你正试图同时测试这个方法和其他方法......当你可能只需要独立测试每个......但我不能确定,因为您没有包含您尝试编写的规范示例(即使它不工作),以及“其他方法”之一的代码和规范示例。即-我们很难调试您的代码的口头描述:) 请编辑您的问题并添加所有相关的代码部分:)
-
谢谢@TarynEast 我已经从代码示例中添加了sn-ps。我正在尝试独立测试这些方法。如何模拟第一种方法返回的
tasks,以便我可以将其用作第二种方法的输入(我实际上对测试感兴趣) -
我的第一印象是你的方法真的很长,可能需要拆分成更小的方法。试着让你的方法不超过 3-4 行。如果它更大 - 然后分成其他方法。例如,“tasks.each do”中的所有内容都应该是一种方法(将单个任务和“区域任务”作为参数传递,并返回“区域任务”的更新版本)。还将 ordering-by 部分取出到另一个以“district_tasks”为参数并传递有序集的方法中。
-
那么你要测试的东西就更少了——你可以测试第一个(数据整理)方法是否需要 one 任务并做好准备。然后,您可以独立于数据整理方法测试排序方法。然后就可以测试整体方法是否为每个任务运行一次该方法,然后调用排序方法...
-
好的,谢谢。 +100。效果很好。
标签: ruby-on-rails ruby postgresql rspec mocking