ruby - 测试 lambda

标签 ruby unit-testing testing lambda rspec

我正在创建一个将 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

最佳答案

一些有趣的问题。一些注意事项:

  1. 您可能不应该在 lambda 中有返回值。只做最后一句话 [h]。
  2. 如果我正确理解代码,您的 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']
    
  3. 看起来您的 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
    
  4. 在不知道基本原理的情况下,很难说您应该将这段代码放在哪里。我的直觉是,这不是 CSV 解析器的工作(尽管一个好的解析器可能会检测 float 并将它们从字符串转换?)保持您的 CSV 解析器可重用。 (注意:重读,我认为你自己已经回答了这个问题——它是业务逻辑,与模型相关联。跟着你的直觉走!)

  5. 最后,您要定义方法 CsvParser.create。您无需扩展 CsvParser 即可访问它,但如果您在 CsvParser 中有其他功能,请考虑使 CsvParser.create 成为一个普通的模块方法,称为 create_from_csv_file

关于ruby - 测试 lambda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10104316/

相关文章:

ruby-on-rails - Array.join ("\n") 不是用换行符加入的方式吗?

ruby - 当第一个条件为假时,ruby 是否停止评估 if 语句?

c# - 如何重构静态方法以便测试我的方法?

unit-testing - 使用 Liferay 进行测试驱动开发

c - 在c中测试空队列

testing - 复制较差的 Wi-Fi 进行测试

ruby - 日期、日期时间和时区

ruby-on-rails - RoR - 外键设置为 nil 后记录保存失败

c# - 在抽象通用测试类中定义单元测试

python - 如何对过滤器进行单元测试?