Тестирование образцов с помощью 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