ruby-on-rails - pruebas - ruby on rails test
Rspec, Rails: ¿cómo probar métodos privados de controladores? (10)
Tengo el controlador:
class AccountController < ApplicationController
def index
end
private
def current_account
@current_account ||= current_user.account
end
end
¿Cómo probar el método privado current_account
con rspec?
PD: uso Rspec2 y Ruby on Rails 3
¿Dónde se usa el método current_account? ¿Para qué sirve?
En general, no prueba métodos privados sino que prueba los métodos que llaman el privado.
Las pruebas unitarias de métodos privados parecen demasiado fuera de contexto con el comportamiento de la aplicación.
¿Estás escribiendo tu código de llamada primero? Este código no se llama en tu ejemplo.
El comportamiento es: quieres un objeto cargado desde otro objeto.
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
¿Por qué quieres escribir la prueba fuera de contexto del comportamiento que deberías tratar de describir?
¿Este código se usa en muchos lugares? ¿Necesita un enfoque más genérico?
https://www.relishapp.com/rspec/rspec-rails/v/2-8/docs/controller-specs/anonymous-controller
No debe probar sus métodos privados directamente, pueden y deben probarse indirectamente mediante el uso del código de métodos públicos.
Esto le permite cambiar las partes internas de su código más adelante sin tener que cambiar sus pruebas.
Puede hacer que sus métodos privados o protegidos sean públicos:
MyClass.send(:public, *MyClass.protected_instance_methods)
MyClass.send(:public, *MyClass.private_instance_methods)
Simplemente coloque este código en su clase de prueba sustituyendo su nombre de clase. Incluya el espacio de nombres si corresponde.
Sé que esto es un poco hacky, pero funciona si quieres que los métodos sean comprobables por rspec pero no visibles en 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
Ahora, cuando puedes ejecutar, tienes las siguientes especificaciones:
RAILS_ENV=test bundle exec rspec spec/foo_spec.rb
Si necesita probar una función privada, cree un método público que invoca el privado.
Use #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
Use la gema rspec-context-private para hacer públicos temporalmente los métodos privados dentro de un contexto.
gem ''rspec-context-private''
Funciona al agregar un contexto compartido a su proyecto.
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
Luego, si pasa :private
como metadato a un bloque de describe
, los métodos privados serán públicos dentro de ese contexto.
describe AccountController, :private do
it ''can test private methods'' do
expect{subject.current_account}.not_to raise_error
end
end
Yo uso el método de envío. P.ej:
event.send(:private_method).should == 2
Porque "enviar" puede llamar a métodos privados
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