我正在创建一个将 CSV 文件导入到多个表中的导入功能。我制作了一个名为 CsvParser
的模块,它可以解析 CSV 文件并创建记录。接收创建操作的模型扩展了CsvParser
。他们调用 CsvParser.create
并传递正确的属性顺序和一个名为 value_parser
的可选 lambda。此 lambda 将散列中的值转换为首选格式。
class Mutation < ActiveRecord::Base
extend CsvParser
def self.import_csv(csv_file)
attribute_order = %w[reg_nr receipt_date reference_number book_date is_credit sum balance description]
value_parser = lambda do |h|
h["is_credit"] = ((h["is_credit"] == 'B') if h["is_credit"].present?)
h["sum"] = -1 * h["sum"].to_f unless h["is_credit"]
return [h]
end
CsvParser.create(csv_file, self, attribute_order, value_parser)
end
end
我在 CsvParser.create
方法中使用 lambda 而不是检查的原因是因为 lambda 就像属于此模型的业务规则。
我的问题是我应该如何测试这个 lambda。我应该在模型或 CsvParser 中测试它吗?我应该测试 lambda 本身还是 self.import
方法数组的结果?也许我应该制作另一个代码结构?
我的 CsvParser 如下所示:
require "csv"
module CsvParser
def self.create(csv_file, klass, attribute_order, value_parser = nil)
parsed_csv = CSV.parse(csv_file, col_sep: "|")
records = []
ActiveRecord::Base.transaction do
parsed_csv.each do |row|
record = Hash.new {|h, k| h[k] = []}
row.each_with_index do |value, index|
record[attribute_order[index]] = value
end
if value_parser.blank?
records << klass.create(record)
else
value_parser.call(record).each do |parsed_record|
records << klass.create(parsed_record)
end
end
end
end
return records
end
end
我正在测试模块本身: 需要'spec_helper'
describe CsvParser do
it "should create relations" do
file = File.new(Rails.root.join('spec/fixtures/files/importrelaties.txt'))
Relation.should_receive(:create).at_least(:once)
Relation.import_csv(file).should be_kind_of Array
end
it "should create mutations" do
file = File.new(Rails.root.join('spec/fixtures/files/importmutaties.txt'))
Mutation.should_receive(:create).at_least(:once)
Mutation.import_csv(file).should be_kind_of Array
end
it "should create strategies" do
file = File.new(Rails.root.join('spec/fixtures/files/importplan.txt'))
Strategy.should_receive(:create).at_least(:once)
Strategy.import_csv(file).should be_kind_of Array
end
it "should create reservations" do
file = File.new(Rails.root.join('spec/fixtures/files/importreservering.txt'))
Reservation.should_receive(:create).at_least(:once)
Reservation.import_csv(file).should be_kind_of Array
end
end
最佳答案
一些有趣的问题。一些注意事项:
- 您可能不应该在 lambda 中有返回值。只做最后一句话 [h]。
如果我正确理解代码,您的 lambda 的第一行和第二行过于复杂。减少它们以使它们更具可读性和更易于重构:
h["is_credit"] = (h['is_credit'] == 'B') # I *think* that will do the same h['sum'] = h['sum'].to_f # Your original code would have left this a string h['sum'] *= -1 unless h['is_credit']
看起来您的 lambda 不依赖于任何外部(
h
除外),因此我将单独对其进行测试。您甚至可以将其设为常量:class Mutation < ActiveRecord::Base extend CsvParser # <== See point 5 below PARSE_CREDIT_AND_SUM = lambda do |h| h["is_credit"] = (h['is_credit'] == 'B') h['sum'] = h['sum'].to_f h['sum'] *= -1 unless h['is_credit'] [h] end
在不知道基本原理的情况下,很难说您应该将这段代码放在哪里。我的直觉是,这不是 CSV 解析器的工作(尽管一个好的解析器可能会检测 float 并将它们从字符串转换?)保持您的 CSV 解析器可重用。 (注意:重读,我认为你自己已经回答了这个问题——它是业务逻辑,与模型相关联。跟着你的直觉走!)
最后,您要定义方法
CsvParser.create
。您无需扩展 CsvParser 即可访问它,但如果您在 CsvParser 中有其他功能,请考虑使CsvParser.create
成为一个普通的模块方法,称为 create_from_csv_file
关于ruby - 测试 lambda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10104316/