Rspec, Rails: как тестировать частные методы контроллеров?
У меня есть контроллер:
class AccountController < ApplicationController
def index
end
private
def current_account
@current_account ||= current_user.account
end
end
Как проверить закрытый метод current_account
с помощью rspec?
P.S. Я использую Rspec2 и Ruby on Rails 3
Ответы
Ответ 1
Используйте #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
Ответ 2
Я использую метод отправки. Например:
event.send(:private_method).should == 2
Поскольку "send" может вызывать частные методы
Ответ 3
Где используется метод current_account? Какую цель он выполняет?
Как правило, вы не проверяете частные методы, а скорее проверяете методы, вызывающие частный.
Ответ 4
Вы должны не проверять свои частные методы напрямую, они могут и должны тестироваться косвенно, используя код из общедоступных методов.
Это позволяет вам изменять внутренности вашего кода по дороге, не изменяя ваши тесты.
Ответ 5
Вы можете сделать ваши частные или защищенные методы общедоступными:
MyClass.send(:public, *MyClass.protected_instance_methods)
MyClass.send(:public, *MyClass.private_instance_methods)
Просто поместите этот код в свой тестовый класс, заменив имя вашего класса. Включите пространство имен, если это применимо.
Ответ 6
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
Ответ 7
Если вам нужно проверить частную функцию, создайте открытый метод, который вызывает частный.
Ответ 8
Индивидуальные методы тестирования компонентов слишком не соответствуют контексту поведения приложения.
Вы сначала пишете свой код вызова?
Этот код не вызывается в вашем примере.
Поведение: вы хотите, чтобы объект загружался из другого объекта.
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
Почему вы хотите написать тест из контекста из поведения, которое вы
должен пытаться описать?
Используется ли этот код во многих местах?
Нужен более общий подход?
https://www.relishapp.com/rspec/rspec-rails/v/2-8/docs/controller-specs/anonymous-controller
Ответ 9
Используйте rspec-context-private gem, чтобы временно публиковать приватные методы в контексте.
gem 'rspec-context-private'
Он работает, добавив общий контекст в ваш проект.
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
Затем, если вы передадите :private
в качестве метаданных в блок describe
, частные методы будут публичными в этом контексте.
describe AccountController, :private do
it 'can test private methods' do
expect{subject.current_account}.not_to raise_error
end
end
Ответ 10
Я знаю, что это своего рода хакерство, но оно работает, если вы хотите, чтобы методы проверялись rspec, но не были видны в 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
Теперь, когда вы можете запускать, вы имеете такие же параметры:
RAILS_ENV=test bundle exec rspec spec/foo_spec.rb