1

J'ai trois modèles:RSpec ne pas voir des modifications à l'objet ActiveRecord avec `changement (objet,: le message)` syntaxe

  • User
  • Company
  • Commitment

Commitment est un HABTM joindre table pour Users et Companies (soit lorsqu'un User joint un Company, il crée un nouveau Commitment). Il a également quelques colonnes/attributs supplémentaires:

  • admin (ne l'utilisateur a des privilèges d'administrateur pour cette entreprise?)
  • confirmed_by_admin (a un administrateur de la société a confirmé la demande de l'utilisateur à se joindre à l'entreprise?)
  • confirmed_by_member (a l'utilisateur lui-même confirmé une invitation à se joindre à la société?)

J'ai aussi défini une méthode pratique pour déterminer rapidement si un engagement est pleinement confirmé:

class Commitment < ApplicationRecord 
    def confirmed? 
    confirmed_by_admin? && confirmed_by_member? 
    end 
end 

Maintenant, j'écris une spécification de demande, mais pour une raison quelconque, le change matcher fonctionne uniquement avec l'un de ses deux syntaxes:

let :carol { FactoryGirl.create(:user) } 
let :company { FactoryGirl.create(:company) } 

it 'confirms invitation to join company' do 
    # Initialize unconfirmed commitment 
    FactoryGirl.create(:commitment, user: carol, 
            company: company, 
            confirmed_by_admin: true) 

    expect do 
    patch commitment_path(carol.commitments.first), 
      params: { commitment: { confirmed_by_member: true } } 

    # for the following syntaxes, ------------------------------------------------ 
    # this works: 
    end.to change { carol.commitments.first.confirmed?) }.from(false).to(true) 
    # and this fails: 
    end.to change(carol.commitments.first, :confirmed?).from(false).to(true) 
    # ---------------------------------------------------------------------------- 

end 

Il semble que carol.commitments.first n'est pas rechargées lorsque RSpec tests pour le changement - Je reçois la sortie de test suivante:

Failure/Error: 
    expect do 
    patch commitment_path(carol.commitments.first), 
      params: { commitment: { confirmed_by_member: true } } 
    end.to change(Commitment.find_by(user: carol, company: company), :confirmed?).from(false).to(true) 

    expected #confirmed? to have changed from false to true, but did not change 
# ./spec/requests/commitments_spec.rb:69:in `block (3 levels) in <top (required)>' 

Ce qui donne? Clairement, je peux juste m'en tenir à la syntaxe bouclés-accolades/blocs, mais j'aimerais comprendre pourquoi on travaille et pas l'autre.

Répondre

2

Lors de l'inspection docs et d'essayer moi-même un nouveau projet de rails reproduisant vos scénarios, et aussi défaut, je crois que la raison pour laquelle il a été un échec parce que

  • la forme de .change « bloc » est couru deux fois (« avant » et « après » le bloc expect), tout ce qui est à l'intérieur de ce bloc:

    .change{ carol.commitments.first.confirmed? }

  • alors que la forme "méthode" de .change est exécutée une fois pour le premier argument: carol.commitments.first, mais a été exécutée deux fois pour le second argument :confirmed?. Cependant, le problème avec ceci est que le carol.commitments.first à ce stade dans le fichier spec ne partage pas le même espace mémoire que cet objet qui a été réellement mis à jour dans votre commitments_controller#update (très probablement cet objet est nommé @commitment). Bien qu'il s'agisse du même enregistrement Commitment, il s'agit d'instances distinctes et les valeurs d'attribut de l'autre ne changent pas automatiquement lorsque l'autre a changé.

Considérez ce qui suit qui montre un scénario dans lequel cette « méthode » formulaire:

it 'sometest' do 
    commitment = FactoryGirl.create(:commitment, user: carol, 
            company: company, 
            confirmed_by_admin: true) 
    expect do 
    # this commitment object is exactly the same object passed in the `change` below 
    commitment.confirmed_by_member = true 
    end.to change(commitment, :confirmed?).from(false).to(true) 
end 

Disclaimer: Ce n'est pas vérifiée, mais parce qu'il me était trop complexe pour écrire un commentaire (avec tout le code de test de l'échantillon), je l'ai écrit ici comme une réponse. Si quelqu'un sait mieux, s'il vous plaît faites le moi savoir.

+0

Oui, je pense que c'est tout. –

+0

Cela semble être l'explication la plus probable - que le modificateur 'change' ne recharge pas l'objet ActiveRecord qui lui est passé après la fin du bloc' expect'. Je vais déposer un problème sur GitHub juste pour vérifier, mais je suis prêt à marquer ceci résolu à moins que quelqu'un d'autre ait un aperçu plus vérifiable. –

+0

Merci pour les commentaires! Il est bon de savoir que vous avez pensé la même chose :) –