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
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
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
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.
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.
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.
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
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
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
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
Si vous devez tester une fonction privée, créez une méthode publique qui appelle la méthode privée.