Rspec-rails: Attendez-vous à ce que l'action change l'attribut d'objet en quelque chose

Créé le 8 janv. 2020  ·  5Commentaires  ·  Source: rspec/rspec-rails

Votre demande de fonctionnalité est-elle liée à un problème ?
Il semble que la façon la plus courante de vérifier si un attribut a changé consiste à vérifier si la valeur de cet attribut correspond à ce que vous attendiez.
Ce n'est pas clair pour moi car parfois vous n'êtes pas sûr de la valeur initiale de cet attribut et vous ne voulez pas commencer à vérifier les usines juste pour le confirmer.

Décrivez la solution que vous souhaitez
Ce serait bien si nous avions un matcher qui vérifie si un nom d'attribut a changé en quelque chose, ou pas autrement.
Par exemple expect { update_user }.to change(user.reload, :name).to 'Kaka Ruto' et expect { update_user }.not_to change(user.reload, :name).to 'Kaka Ruto'

Décrivez les alternatives que vous avez envisagées
J'ai dû vérifier si la valeur de cet attribut est égale à ce que j'attends. Par exemple
expect(user.reload.name).to eq 'Kaka Ruto'

Contexte supplémentaire
J'ai essayé d'utiliser les change matchers existants mais j'ai eu un comportement inattendu.
Pour ce test, expect { update_user }.to change(user.reload, :name).to 'Kaka Ruto' , j'ai obtenu une spécification défaillante avec la description expected 'User#name' to have changed to "Kaka Ruto", but did not change . Cependant, il s'agit de passes de variantes annulées ! Ce expect { update_user }.not_to change(user.reload, :name) passe en fait

Commentaire le plus utile

Pour éviter le double rechargement vous pouvez aussi faire :

expect { update_user; user.reload }.to change { user.name }.to 'Kaka Ruto'

Tous les 5 commentaires

Le problème avec ce code est que reload est envoyé avant le changement.
Donc en gros ça :

expect { update_user }.to change(user.reload, :name).to 'Kaka Ruto'

s'étend à :

object = user.reload
old_value = object.send(:name)
update_user
new_value = object.send(:name)
expect(new_value).not_to eq(old_value) # i.e. "change"
expect(new_value).to eq('Kaka Ruto')

Ici, nous avons deux problèmes. La première est que reload est exécuté avant le changement. Vous vous attendiez probablement à ce qu'il se recharge après le changement.
Et une autre est que vous devez faire un rechargement, quelque chose dans votre code au lieu d'utiliser le modèle le trouve par id et le réinstancie à partir de zéro, donc celui instancié en test est désynchronisé avec celui du code testé vous obligeant à recharger.

Je vous propose d'utiliser :

expect { update_user }.to change { user.reload.name }.to 'Kaka Ruto'

Cela a un inconvénient que reload est exécuté deux fois, avant le changement et après.
J'ai vu quelque chose comme change_reloaded(model, attribute_name) matcher qui enregistre la valeur pour comparaison avant le changement, puis recharge et compare après le changement.
Cependant, le problème que update_user charge le modèle à partir de la base de données persiste.

N'hésitez pas à rouvrir si vous estimez que rspec-rails est incomplet ou présente un défaut.

Merci @pirj ! Cela aide en effet.

Vous êtes toujours les bienvenus!

Pour éviter le double rechargement vous pouvez aussi faire :

expect { update_user; user.reload }.to change { user.name }.to 'Kaka Ruto'

@JonRowe chouette !

Cette page vous a été utile?
0 / 5 - 0 notes