Comment configurer des associations de modèles dans un test RSpec?
-
10-07-2019 - |
Question
J'ai collé les spécifications que j'ai écrites pour l'affichage posts / show.html.erb une application que je suis en train d'écrire comme un moyen d'apprendre RSpec. Je suis encore en train d'apprendre à se moquer et à se moquer. Cette question est spécifique au " devrait lister tous les commentaires associés " spec.
Ce que je veux, c'est vérifier que l'affichage montre les commentaires d'un article. Mais ce dont je ne suis pas sûr, c'est comment configurer ce test et le faire parcourir ensuite devrait contenir des instructions ('xyz'). Des allusions? D'autres suggestions sont également appréciées! Merci.
--- Modifier
Quelques informations supplémentaires. J'ai un named_scope appliqué aux commentaires dans ma vue (je sais, je l'ai fait un peu en arrière dans ce cas), donc @ post.comments.approved_is (true). Le code collé répond par l'erreur "Méthode non définie` approuvée_pour # # '", ce qui est logique, car je lui ai dit de remplacer les commentaires et de renvoyer un commentaire. Je ne sais toujours pas comment enchaîner les stubs de manière à ce que @ post.comments.approved_is (true) renvoie un tableau de commentaires.
La solution
Stubbing est vraiment la voie à suivre ici.
À mon avis, tous les objets des spécifications du contrôleur et de la vue doivent être tronqués avec des objets fictifs. Il n’est pas vraiment nécessaire de passer du temps à tester de manière redondante une logique qui devrait déjà faire l’objet de tests approfondis dans les spécifications de votre modèle.
Voici un exemple de configuration des spécifications dans votre Pastie…
describe "posts/show.html.erb" do
before(:each) do
assigns[:post] = mock_post
assigns[:comment] = mock_comment
mock_post.stub!(:comments).and_return([mock_comment])
end
it "should display the title of the requested post" do
render "posts/show.html.erb"
response.should contain("This is my title")
end
# ...
protected
def mock_post
@mock_post ||= mock_model(Post, {
:title => "This is my title",
:body => "This is my body",
:comments => [mock_comment]
# etc...
})
end
def mock_comment
@mock_comment ||= mock_model(Comment)
end
def mock_new_comment
@mock_new_comment ||= mock_model(Comment, :null_object => true).as_new_record
end
end
Autres conseils
Je ne suis pas sûr que ce soit la meilleure solution, mais j’ai réussi à faire passer les spécifications en écrasant simplement le named_scope. J'apprécierais vos réactions à ce sujet ainsi que vos suggestions pour une meilleure solution, étant donné qu'il en existe un.
it "should list all related comments" do
@post.stub!(:approved_is).and_return([Factory(:comment, {:body => 'Comment #1', :post_id => @post.id}),
Factory(:comment, {:body => 'Comment #2', :post_id => @post.id})])
render "posts/show.html.erb"
response.should contain("Joe User says")
response.should contain("Comment #1")
response.should contain("Comment #2")
fin
Il lit un peu méchant.
Vous pouvez faire quelque chose comme:
it "shows only approved comments" do
comments << (1..3).map { Factory.create(:comment, :approved => true) }
pending_comment = Factory.create(:comment, :approved => false)
comments << pending_comments
@post.approved.should_not include(pending_comment)
@post.approved.length.should == 3
end
Ou quelque chose du genre. Spécifiez le comportement, une méthode approuvée doit renvoyer les commentaires approuvés pour une publication. Cela pourrait être une méthode simple ou un named_scope. Et en attente ferait quelque chose d'évident aussi.
Vous pouvez également avoir une usine pour: pending_comment, par exemple:
Factory.define :pending_comment, :parent => :comment do |p|
p.approved = false
end
Ou, si false est la valeur par défaut, vous pouvez faire la même chose pour: created_comments.
J'aime beaucoup l'approche de Nick. J'ai eu le même problème moi-même et j'ai pu faire ce qui suit. Je pense que mock_model fonctionnerait aussi bien.
post = stub_model(Post)
assigns[:post] = post
post.stub!(:comments).and_return([stub_model(Comment)])