2017-01-19 4 views
2

Je suis conscient que expect(assign(:var)) dans les spécifications de contrôleur vérifie que @var est affecté à une certaine valeur. Dans mon cas, je veux tester si ce @var reçoit un message spécifique. Si je le fais avant get :action les affectations renvoie zéro. Si je le fais après, il est trop tard pour attendre le message.RSpec test d'une variable d'instance de contrôleur reçoit un message

# controller 
def action 
    @var = something 
    @var.message 
    render :nothing 
end 

# spec1 
expect(assigns(:var)).to receive(:message) # not working, var is nil 
get :action 

# spec2 
get :action 
expect(assigns(:var)).to receive(:message) # not working, expectation too late 

Répondre

2

Ce que vous cherchez ici est double ou mock. Vous pouvez utiliser ceux-ci en ajoutant la gemme rspec-mocks ou un autre gemme double test comme RR.

Une fois que vous avez un de ces (j'utilise RR), vous pouvez le faire (syntaxe pour RR):

mock(assigns(:var)).foo 
get :action 

pas 100% sûr sur la syntaxe de rspec-mocks mais il devrait ressembler à ceci :

var = double(assigns(:var)) 
expect(var).to receive(:foo) 
get :action 

vous devriez regarder le README pour Message Expectations et Expecting Arguments si vous avez besoin d'ajouter d'autres contrôles.

+0

Essayé en utilisant rspec-mocks mais cela n'a pas fonctionné, ou je ne pouvais pas comprendre comment il devrait être écrit: 'var = spy (assigne (: var), action: 1); get: action, id: 10; expect (var) .to have_received (: action) ' – hammady

+0

Malheureusement,' assigns (: var) 'retournera' nil' s'il est appelé avant le 'get: action' et c'est tout le point dans ma question. Pour cela j'ai essayé 'spy' au lieu de' double 'qui ne fonctionnait pas non plus. – hammady

+0

Peut-être essayer '@ var' au lieu de' assigns (: var) '? –

0

Puisque la variable est assignée et appelée dans la même méthode dans le contrôleur, je ne crois pas que vous ayez un moyen de l'attraper entre les deux et de la simuler.

Au lieu de cela je me attends habituellement avec « any_instance_of » comme ceci:

expect_any_instance_of(ClassOfVar).to receive(:message) 
+0

Bien que l'attente d'une instance puisse fonctionner, il n'est pas prudent de supposer que n'importe quelle instance pourrait recevoir le message et que le test passerait. – hammady

+1

Je suis d'accord que ça ne marchera pas dans tous les cas, et que ce n'est pas parfait, mais ça marche dans la plupart des cas, et c'est la seule solution au problème que vous décrivez, que je connais :-) Je suis excité de voir si quelqu'un d'autre a la solution parfaite à votre problème sans inconvénients, mais pour l'instant c'est le meilleur que j'ai pu trouver :-) – kaspernj

0

Je forçais actuellement la variable d'instance de contrôleur pour attendre les messages sur. Bien que cela fonctionne, mais il ignore la logique de chargement (cancan), je donc créé un autre test que:

it "loads and authorizes object" do 
    get :action, id: 10 
    assert_response :success 
    end 

    it "calls action on object" do 
    controller.instance_variable_set('@var', @my_real_object_or_mock_here) 
    expect(@my_real_object_or_mock_here).to receive(:message) 
    get :action, id: 10 
    assert_response :success 
    end 

Je trouve un peu cette solution hacky, mais si cette réponse obtient le plus de voix, je vais l'accepter: