web-dev-qa-db-fra.com

Rspec, Rails: comment tester les méthodes privées des contrôleurs?

J'ai contrôleur:

class AccountController < ApplicationController
  def index
  end

  private
  def current_account
    @current_account ||= current_user.account
  end
end

Comment tester la méthode privée current_account avec rspec?

P.S. J'utilise Rspec2 et Ruby sur Rails 3

123
petRUShka

Utilisez #instance_eval

@controller = AccountController.new
@controller.instance_eval{ current_account }   # invoke the private method
@controller.instance_eval{ @current_account }.should eql ... # check the value of the instance variable
191
monocle

J'utilise la méthode d'envoi. Par exemple:

event.send(:private_method).should == 2

Parce que "send" peut appeler des méthodes privées

37
graffzon

Où la méthode current_account est-elle utilisée? A quoi est-ce que ça sert?

Généralement, vous ne testez pas les méthodes privées, mais plutôt les méthodes qui appellent les méthodes privées.

23
Ryan Bigg

Vous devriez pas tester vos méthodes privées directement, elles peuvent et doivent être testées indirectement en utilisant le code issu de méthodes publiques.

Cela vous permet de modifier les éléments internes de votre code ultérieurement sans avoir à modifier vos tests.

8
Lorem Ipsum Dolor

Vous pouvez vous rendre privé ou protégé comme méthodes publiques:

MyClass.send(:public, *MyClass.protected_instance_methods) 
MyClass.send(:public, *MyClass.private_instance_methods)

Il suffit de placer ce code dans votre classe de test en remplaçant votre nom de classe. Incluez l'espace de noms, le cas échéant.

4
zishe
require 'spec_helper'

describe AdminsController do 
  it "-current_account should return correct value" do
    class AccountController
      def test_current_account
        current_account           
      end
    end

    account_constroller = AccountController.new
    account_controller.test_current_account.should be_correct             

   end
end
3
speedingdeer

Utilisez le gsp rspec-context-private pour rendre temporairement publiques les méthodes privées dans un contexte.

gem 'rspec-context-private'

Cela fonctionne en ajoutant un contexte partagé à votre projet.

RSpec.shared_context 'private', private: true do

  before :all do
    described_class.class_eval do
      @original_private_instance_methods = private_instance_methods
      public *@original_private_instance_methods
    end
  end

  after :all do
    described_class.class_eval do
      private *@original_private_instance_methods
    end
  end

end

Ensuite, si vous passez :private comme métadonnées dans un bloc describe, les méthodes privées seront publiques dans ce contexte.

describe AccountController, :private do
  it 'can test private methods' do
    expect{subject.current_account}.not_to raise_error
  end
end
1
barelyknown

Le test unitaire des méthodes privées semble trop hors contexte avec le comportement de l'application.

Vous écrivez votre code d'appel en premier? Ce code n'est pas appelé dans votre exemple.

Le comportement est le suivant: vous voulez qu'un objet soit chargé à partir d'un autre objet.

context "When I am logged in"
  let(:user) { create(:user) }
  before { login_as user }

  context "with an account"
    let(:account) { create(:account) }
    before { user.update_attribute :account_id, account.id }

    context "viewing the list of accounts" do
      before { get :index }

      it "should load the current users account" do
        assigns(:current_account).should == account
      end
    end
  end
end

Pourquoi voulez-vous écrire le test hors contexte dans le comportement que vous devriez essayer de décrire?

Ce code est-il utilisé dans de nombreux endroits? Besoin d'une approche plus générique?

https://www.relishapp.com/rspec/rspec-Rails/v/2-8/docs/controller-specs/anonymous-controller

1
Brent Greeff

Je sais que c'est un peu hacky, mais cela fonctionne si vous voulez que les méthodes puissent être testées par rspec mais ne soient pas visibles dans prod.

class Foo
  def public_method
    #some stuff
  end

  eval('private') unless Rails.env == 'test'

  def testable_private_method
    # You can test me if you set Rails_ENV=test
  end 
end

Maintenant, quand vous pouvez lancer votre travail, vous êtes comme suit:

Rails_ENV=test bundle exec rspec spec/foo_spec.rb 
0
onetwopunch

Si vous devez tester une fonction privée, créez une méthode publique qui appelle la méthode privée.

0
liamfriel