Rspec, Rails: ¿cómo probar métodos privados de controladores?


Tengo 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?

P.d. Yo uso Rspec2 y Ruby on Rails 3

Author: Ryan Bigg, 2010-11-25

10 answers

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
 185
Author: monocle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-24 21:48:40

Uso el método send. Eg:

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

Porque "send" puede llamar a métodos privados

 37
Author: graffzon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-28 23:19:29

¿Dónde se utiliza el método current_account? Para qué sirve?

Generalmente, no se prueban métodos privados, sino que se prueban los métodos que llaman al privado.

 23
Author: Ryan Bigg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-24 21:29:57

Debe no probar sus métodos privados directamente, pueden y deben probarse indirectamente mediante el ejercicio del código de métodos públicos.

Esto le permite cambiar el funcionamiento interno de su código en el futuro sin tener que cambiar sus pruebas.

 8
Author: Xinyang Li,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-17 08:56:45

Usted podría hacer que los métodos privados o protegidos como 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.

 4
Author: zishe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-28 22:41:00
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
Author: speedingdeer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-04 14:35:18

Los métodos privados de pruebas unitarias 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 su ejemplo.

El comportamiento es: desea que se cargue un objeto 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é u quiere escribir la prueba fuera de contexto desde el comportamiento que debería estar tratando de describir?

¿Este código se usa en muchos lugares? Necesita un más genérico ¿acercarnos?

Https://www.relishapp.com/rspec/rspec-rails/v/2-8/docs/controller-specs/anonymous-controller

 1
Author: Brent Greeff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-14 22:53:55

Use la gema rspec-context-private para hacer públicos temporalmente los métodos privados dentro de un contexto.

gem 'rspec-context-private'

Funciona añadiendo un contexto compartido a tu 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

Entonces, si pasa :private como metadatos a un bloque 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
 1
Author: barelyknown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-24 17:24:30

Si necesita probar una función privada, cree un método público que invoque la función privada.

 1
Author: liamfriel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-18 23:42:41

Sé que esto es un poco hackeado, pero funciona si quieres los métodos 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 se puede ejecutar usted es spec así:

RAILS_ENV=test bundle exec rspec spec/foo_spec.rb 
 0
Author: onetwopunch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-05 23:44:44