2010-12-01 29 views
1

J'ai un problème de moquerie. J'ai la classe DistanceMatrix et je voudrais d'indiquer quelle méthode form_matrix a été appelée if/else instruction. J'ai besoin d'utiliser moka et RSpec. Des idées?Rubis. Mocking in RSpec

class DistanceMatrix 

def initialize(*args) 
    if args[0].class == String 
     form_matrix(get_data_from_yaml(args[0], args[1])) 
    elsif args[0].class == Array || args[0] == nil 
     form_matrix(get_data_from_db(args[0])) 
    end 
end 

def form_matrix(...) 
    ... 
end 

end 

a essayé:

describe DistanceMatrix, "when mocking ..." do 
    it "should do call form_matrix" do 
    DistanceMatrix.any_instance.expects(:form_matrix).with([1]).once 
    DistanceMatrix.any_instance.expects(:get_data_from_yaml).with("file_name.yml").once.returns([1]) 
    DistanceMatrix.new("file_name.yml") 
    end 
end 

mais nous avons eu erreur:

Failures: 
    1) DistanceMatrix when mocking ... should do call form_matrix 
    Failure/Error: DistanceMatrix.new("file_name.yml") 
    unexpected invocation: #<AnyInstance:DistanceMatrix>.get_data_from_yaml('file_name.yml', nil) 
    unsatisfied expectations: 
    - expected exactly once, not yet invoked: #<AnyInstance:DistanceMatrix>.get_data_from_yaml('file_name.yml') 
    - expected exactly once, not yet invoked: #<AnyInstance:DistanceMatrix>.form_matrix([1]) 
    satisfied expectations: 
    - allowed any number of times, already invoked once: #<DistanceMatrix:0x9e48b40>.get_optimal_route(any_parameters) 
    - allowed any number of times, already invoked once: #<Database::Distances:0x9d59798>.load_distances(any_parameters) 
    # ./distance_matrix.rb:18:in `initialize' 
    # ./tsp_algorithm_spec.rb:253:in `new' 
    # ./tsp_algorithm_spec.rb:253:in `block (2 levels) in <top (required)>' 
Finished in 0.25979 seconds 

Je trouve que nous devrions utiliser RSpec pas .expects() mais .should_receive(), donc j'ai essayé :

describe DistanceMatrix, "when mocking ..." do 
    it "should do call form_matrix" do 
    DistanceMatrix.any_instance.should_receive(:form_matrix).with([1]) 
    DistanceMatrix.any_instance.should_receive(:get_data_from_yaml).with("file_name.yml").and_return([1]) 
    DistanceMatrix.new("file_name.yml") 
    end 
end 

mais un nouvel échec a été détecté:

Failures: 
    1) DistanceMatrix when mocking ... should do call form_matrix 
    Failure/Error: DistanceMatrix.any_instance.should_receive(:form_matrix).with([1]) 
    (#<Mocha::ClassMethods::AnyInstance:0x96356b0>).form_matrix([1]) 
     expected: 1 time 
     received: 0 times 
    # ./tsp_algorithm_spec.rb:251:in `block (2 levels) in <top (required)>' 

Finished in 0.26741 seconds 
+0

#should_receive utilise le moqueur de rspec - vous avez dit à l'origine que vous utilisiez mocha. Si vous voulez utiliser moka, vous devez le configurer dans spec_helper.rb pour votre projet. – karmajunkie

+0

Ce que ces deux erreurs vous disent, c'est que form_matrix n'a pas été appelée comme prévu. Je ne pense pas que le problème soit avec votre test.Ma conjecture est que ce que vous passez dans l'initialiseur est une chaîne enveloppée ou quelque chose, donc args [0] .class! = String. avez-vous traversé dans un débogueur pour comprendre ce qui se passe? – karmajunkie

+0

Non. Comment puis-je déboguer sur un terminal Linux? – Martynas

Répondre

0
DistanceMatrix.any_instance.expects(:form_matrix).with("String") # => supply the correct string param 

ou

DistanceMatrix.any_instance.expects(:form_matrix).with([]) # => supply the correct array param 

Je ne suis pas sûr de ce que votre get_data_from_db et les méthodes get_data_from_yaml font, mais vous devriez être en mesure de contrôler les entrées et de vérifier les arguments corrects sont fourni à form_matrix.

ÉDITÉ Vous devez utiliser DistanceMatrix.any_instance au lieu de se moquant sur une variable d'instance parce que vous essayez de se moquer de quelque chose dans le initialiseur. En outre, en cas de doute, vous devrez effectuer l'appel de la méthode appropriée après avoir configuré le simulacre dans les lignes ci-dessus, par ex.

DistanceMatrix.new("SomeString") 

ÉDITÉE

it "should do call #form_matrix with proper arguments" do 
    DistanceMatrix.any_instance.expects(:form_matrix).with([1]) 
    DistanceMatrix.any_instance.expects(:get_data_from_yaml).with("foo").returns([1]) 
    DistanceMatrix.new("foo") 
end 
+0

mes deux méthodes get_data_from_yaml et get_data_from_db retournent Array. J'ai essayé ceci: décrire DistanceMatrix, "quand moqueur ..." faire il "devrait ..." faire distance_matrix = DistanceMatrix.any_instance distance_matrix = simulacres distance_matrix.expects (: form_matrix) .Avec (an_instance_of (Array)) DistanceMatrix.new ("nom_fichier.yml", [1, 2, 3]) fin fin mais cela ne fonctionne pas. – Martynas

+0

Ok, dans ce cas, ce que je ferais, c'est mock out les méthodes get_data_from_yaml et get_data_from_db pour retourner deux valeurs connues et définir vos attentes sur ces valeurs connues. voir modification ci-dessus – karmajunkie

+0

J'ai essayé mais j'ai échoué. – Martynas

3

Je n'ai une expérience avec l'utilisation de Mocha et non RSpec, mais en regardant le message d'échec Mocha, les éléments clés sont les suivants: -

unexpected invocation: #<AnyInstance:DistanceMatrix>.get_data_from_yaml('file_name.yml', nil) 
unsatisfied expectations: 
- expected exactly once, not yet invoked: #<AnyInstance:DistanceMatrix>.get_data_from_yaml('file_name.yml') 

Si vous regardez les extrémités de ces lignes, vous remarquerez que get_data_from_yaml n'est pas appelé avec les paramètres attendus. Il est appelé avec ('filename.yml', nil) et non ('filename.yml') comme prévu.

Cela se produit parce que lorsque vous appelez DistanceMatrix.new("file_name.yml") dans votre test avec seulement un argument puis à l'intérieur DistanceMatrix#initializeDistanceMatrix#get_data_from_yaml est appelé à (args[0], args[1]) et depuis args est un ensemble d'éléments, args[1] serez nil.

Peut-être que ce n'est pas comment vous attendiez Ruby à travailler, mais ce qui suit illustre ce comportement: -

def foo(*args) 
    puts "args[0]=#{args[0].inspect}; args[1]=#{args[1].inspect}" 
end 

foo("string") # => args[0]="string"; args[1]=nil