views:

102

answers:

2

I created a module in lib directory and I can freely call the various methods it contains throughout my Rails app (after adding include ModuleName) with no problems.

However when it comes to tests, they complain no such methods exist. I tried including the module into my test helper with no luck. Can anyone help.

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
+4  A: 

There are a couple of different errors here. First, when you create a module and you mix the content of the module into a class, the methods within the module become part of the class itself.

That said, the following line doesn't make sense

assert_redirected_to SpreedlyTools.spreedly_signup_url(user)

Assuming you mixed the module into a User class, you should call the method as

assert_redirected_to User.new.spreedly_signup_url(user)

Also note the new statement. Because you include the module into the class and you don't extend the class, the method become an instance method not a class method.

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

For this reason, the following line doesn't make sense.

class ActiveSupport::TestCase
   include SpreedlyTools
   ....
end
Simone Carletti
my original intention was not to have these methods as part of the user class. Instead they were just general methods available to the whole app. In hindsight, it looks like i should refactor and just make this particular method part of the usre class. However in general should i be able to call methods i define in a module in lib in any of my tests without adding any include / requires or other code?
adam
Only if you follow Ruby autoload rules.
Simone Carletti
Re. first comment: I'd like to add that if your if there's a chance you have to use the spreedly_signup method elsewhere in your application, you might want to consider keeping it as a separate module, and testing the SpreedlyTools separately...no space to explain how to do this in comments though...there are several great questions on stackoverflow explaining how to do this.
btelles
ok im going search more for modules testing and rails. See if i can digg those questions up.
adam
+1  A: 

Ah, it's a subtle problem but easily corrected. Rather than including SpreedlyTools in your test suite you want to test objects that were created by classes that include SpreedlyTools.

In Ruby you may find that Classes work a lot more the way you're thinking Modules work. You can use a class level function by defining it as such:

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

SpreedlyTools.spreedly_signup_url user

This would make sense now.

Modules are for mixing in code to other classes. But if you just want generic tools available at all times you really want class level functions.

Chuck Vose
Sorry if this has already been answered here but im confused. If i include a module i create in /lib in my application_controller can I use the methods in my functional tests and if so what would be the syntax. Outside of tests i can use the methods simply by typing some_method without the need to prefix with the module name i.e. Module::some_method. In tests though im having no luck.
adam