Sto creando una funzione di importazione che importa file CSV in più tabelle. Ho creato un modulo chiamato CsvParser
che analizza un file CSV e crea record. I miei modelli che ricevono le azioni create estende lo CsvParser
. Effettuano una chiamata a CsvParser.create
e passano l'ordine dell'attributo corretto e un lambda opzionale chiamato value_parser
. Questo lambda trasforma i valori in un hash in un formato preffered.Test a 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
La ragione per cui sto usando un lambda al posto di controlli all'interno del metodo CsvParser.create
è perché il lambda è come una regola di business che appartiene a questo modello.
La mia domanda è come dovrei provare questo lambda. Dovrei testarlo nel modello o nel CsvParser? Dovrei testare il lambda stesso o il risultato di un array del metodo self.import
? Forse dovrei fare un'altra struttura di codice?
mio CsvParser appare come segue:
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
sto testando il modulo stesso: richiedono '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
Grazie per la vostra, risposta chiara approfondita. Ho seguito il tuo consiglio ed ho potuto testare la costante perché potevo chiamare Class ::. Mi chiedo solo come dovrei provare qualcosa di simile quando sarebbe una variabile in un metodo. –
Se il lambda non potesse essere refactored, lo testerei come qualsiasi altro metodo. Se si tratta di un lambda molto complicato, basato su molte variabili locali, questo potrebbe indicare che vuole essere la sua istanza. Come regola generale, i metodi difficili da testare necessitano di un refactoring! – user208769
Oggi mi sono reso conto che esiste un qualcosa chiamato oggetto metodo. Può essere usato allo stesso modo di un lambda con l'unica differenza che posso usare il codice di un metodo invece di un lambda.Penso che sia più pulito che definire una lambda come costante. Quindi, invece di passare il lambda come parametro, ora uso il metodo (:) –