Тестирование образцов с помощью rspec
Я создал представления Devise под управлением rails g devise:views
и теперь хотел бы протестировать их.
Вот что я придумал:
require 'spec_helper'
describe "devise/sessions/new" do
before do
render
end
it "renders the form to log in" do
rendered.should have_selector("form", action: user_session_path, method: :post) do |form|
end
end
end
Для оператора render он дает мне undefined local variable or method 'resource'
. После googling вокруг я обнаружил, что должен добавить
@user.should_receive(:resource).and_return(User.new)
перед оператором рендеринга - но он все равно дает мне ту же ошибку, и я не уверен, как его использовать.
Что я делаю неправильно? Благодарим за помощь.
Ответы
Ответ 1
И знаешь? Я нашел этот ответ, где у кого-то была аналогичная проблема. Решение состоит в том, чтобы включить в ваш помощник приложения следующий код:
def resource_name
:user
end
def resource
@resource ||= User.new
end
def devise_mapping
@devise_mapping ||= Devise.mappings[:user]
end
Это необходимо, потому что в его контроллерах метод использует определенные вспомогательные методы. Однако, если я получаю доступ к представлениям из своих спецификаций, эти вспомогательные методы недоступны, поэтому мои тесты терпят неудачу. Помещение этих методов внутри помощника приложения делает их доступными во всем приложении, включая мои спецификации, и действительно тесты проходят!
Ответ 2
Еще одна мысль о том, что кто-то сталкивается с той же проблемой. Я не был большим поклонником добавления кода к моим помощникам, чтобы сделать так, чтобы тесты проходили, поэтому я закончил тем, что добавил этот код в блок перед моими тестами:
before do
view.stub(:resource).and_return(User.new)
view.stub(:resource_name).and_return(:user)
view.stub(:devise_mapping).and_return(Devise.mappings[:user])
end
Ответ 3
Как и Майк Фогг, мне не понравилась идея добавить несколько методов в свой ApplicationController, чтобы получить эти спецификации просмотров.
Я заметил, что моя установка rspec имела каталог spec/mixins
, поэтому я сделал следующее:
# spec/mixins/devise_helpers.rb
module DeviseHelpers
def resource_name
:user
end
def resource
@resource ||= User.new
end
def devise_mapping
@devise_mapping ||= Devise.mappings[:user]
end
end
Затем включите в мою спецификацию:
# spec/views/devise/registrations/new.html.haml_spec.rb
require 'rails_helper'
include DeviseHelpers
describe 'devise/registrations/new.html.haml' do
it 'has a login link for existing users' do
render
expect(rendered).to have_link('Log in')
end
end
Теперь я могу включить эти методы в любую спецификацию, которая им нужна.
Ответ 4
В rspec есть конфигурация, которая не позволяет вам исключать методы, которые не определены. С рельсами 4 это даже стандартное поведение:
# spec/spec_helper.rb
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
Из-за этого самый высокий голос не работает с помощниками-помощниками. Измените verify_partial_doubles
на false
или используйте фактический помощник.
Ответ 5
Я хотел найти решение @MikeFogg - я делаю нечто похожее в другой спецификации представления, чтобы справиться с Pundit - но, конечно, я столкнулся с проблемой, на которую @ChrisEdwards указал в связи с необходимостью mocks.verify_partial_doubles = false
.
Тем не менее, я не очень интересовался отключением этого во всем моем наборе тестов, это хорошая проверка, "обычно рекомендуемая" и по умолчанию в Rspec 4+.
Сначала я опубликовал решение, в котором я переконфигурировал RSpec в блоках до и после, но я наткнулся на очень простой способ сделать это, и он прекрасно работает:
before(:each) do
without_partial_double_verification do
allow(view).to receive(:resource).and_return(Student.new)
allow(view).to receive(:resource_name).and_return(:student)
allow(view).to receive(:devise_mapping).and_return(Devise.mappings[:student])
end
# other before_each configuration here as needed
end
Это было примерно с 2016 года и первоначально называлось without_verifying_partial_doubles
, но было переименовано в текущее without_partial_double_verification
. Кажется, я не вижу документально подтвержденных документов.
Ответ 6
Объединив ответ @sixty4bit с этим ответом, я пришел к такому решению:
class DeviseHelpers < Module
def initialize(resource_name, resource_class)
@resource_name = resource_name
@resource_class = resource_class
end
def extended(base)
_resource_name = @resource_name
_resource_class = @resource_class
base.class_eval do
define_method :resource_name do
_resource_name
end
define_method :resource do
@resource ||= _resource_class.new
end
define_method :devise_mapping do
@devise_mapping ||= Devise.mappings[_resource_name]
end
end
end
end
Это позволяет вам использовать его с различными ресурсами, требуя в верхней части вашей спецификации:
require 'support/devise_helpers'
и затем называя это так:
before do
view.extend(DeviseHelpers.new(:customer, Customer))
end