Rails - Почему я не могу использовать метод, который я создал в модуле в своих тестах?

Я создал модуль в каталоге lib, и я могу свободно вызывать различные методы, которые он содержит в моем приложении Rails (после добавления include ModuleName) без проблем.

Однако, когда дело доходит до тестов, они жалуются, что такие методы не существуют. Я пробовал включить модуль в свой тестовый помощник без везения. Может кто-нибудь помочь.

4) Error:
test_valid_signup_redirects_user_to_spreedly(UsersControllerTest):
NoMethodError: undefined method `spreedly_signup_url' for SpreedlyTools:Module
    /test/functional/user_controller_test.rb:119:in `test_valid_signup_redirects_user_to_spreedly'

module SpreedlyTools
  protected
  def spreedly_signup_url(user)
    return "blahblah"
  end
end

class ApplicationController < ActionController::Base


  helper :all # include all helpers, all the time
  protect_from_forgery # See ActionController::RequestForgeryProtection for details
  include SpreedlyTools
  ....
end

ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'test_help'

class ActiveSupport::TestCase
   include SpreedlyTools
   ....
end

require File.dirname(__FILE__) + '/../test_helper'
require 'users_controller'

# Re-raise errors caught by the controller.
class UsersController; def rescue_action(e) raise e end; end

class UsersControllerTest < ActionController::TestCase
....

  def test_valid_signup_redirects_user_to_spreedly
    get :new
    assert_response :success
    post :create, :user =>  {:first_name => "bobby",
                      :last_name => "brown",
                      :email => "[email protected]",
                      :email_confirmation => "[email protected]",
                      :password => "bobby1",
                      :password_confirmation => "bobby1"}

    assert_response :redirect
    user = assigns(:user)
    assert_redirected_to SpreedlyTools.spreedly_signup_url(user)

  end
end

Ответ 1

Здесь есть несколько разных ошибок. Во-первых, когда вы создаете модуль и смешиваете содержимое модуля с классом, методы внутри модуля становятся частью самого класса.

Тем не менее, следующая строка не имеет смысла

assert_redirected_to SpreedlyTools.spreedly_signup_url(user)

Предполагая, что вы смешали модуль с классом User, вы должны вызвать метод как

assert_redirected_to User.new.spreedly_signup_url(user)

Также обратите внимание на оператор new. Поскольку вы include модуль в классе, а вы не extend класса, метод становится методом экземпляра, а не методом класса.

assert_redirected_to User.new.spreedly_signup_url(user) # valid
assert_redirected_to User.spreedly_signup_url(user) # invalid

По этой причине следующая строка не имеет смысла.

class ActiveSupport::TestCase
   include SpreedlyTools
   ....
end

Ответ 2

А, это тонкая проблема, но она легко исправлена. Вместо того чтобы включать SpreedlyTools в ваш тестовый пакет, вы хотите протестировать объекты, созданные классами, которые включают SpreedlyTools.

В Ruby вы можете обнаружить, что Классы работают намного больше, как вы думаете, что модули работают. Вы можете использовать функцию уровня класса, определяя ее как таковую:

class SpreedlyTools
  def self.spreedly_signup_url user
    ...
  end
end

SpreedlyTools.spreedly_signup_url user

Теперь это будет иметь смысл.

Модули предназначены для смешивания кода с другими классами. Но если вы просто хотите, чтобы универсальные инструменты были доступны в любое время, вам действительно нужны функции уровня класса.