Pregunta

Ok, so my main issue is I have implemented Mailboxer into our project to handle messaging and I am trying to write tests for it. However, I keep stumbling over and over again. I have attempted several different stub/mocks but have made no progress.

We have a conversations_controller.rb that relies on before_filters for setting all the instance variables necessary for doing each action. Then in the controller actions, the instance variables are referenced directly to do any sort of action or to return specific data.

Here is an example of our index action which returns all conversations in the "box" that is specified in the before_filter, of the mailbox also specified in another before_filter:

class ConversationsController < ::ApplicationController
    before_filter :get_user_mailbox, only: [:index, :new_message, :show_message, :mark_as_read, :mark_as_unread, :create_message, :reply_message, :update, :destroy_message, :untrash]
    before_filter :get_box

    def index
      if @box.eql? "inbox"
        @conversations = @mailbox.inbox
      elsif @box.eql? "sentbox"
        @conversations = @mailbox.sentbox
      else
        @conversations = @mailbox.trash
      end
    end

And before filters:

private
def get_user_mailbox
    @user = User.where(:user_name => user.user_name.downcase).where(:email => user.email.downcase).first_or_create
    @mailbox = @user.mailbox if @user
end

def get_box
    if params[:box].blank? or !["inbox","sentbox","trash"].include?params[:box]
      params[:box] = 'inbox'
    end
    @box = params[:box]
end

So I guess I have 2 questions in one. First, how to I get my tests to generate the correct data @mailbox, @user, and @box that is needed for the index action. Next, how do I pass the fake parameter to set @box to different "inbox/sentbox/trash". I have tried controller.index({box: "inbox"}) but always get "wrong arguments 1 for 0" messages.

I have tried the following in various different ways, but always get nil:class errors which means that my instance variables are definitely not being set properly.

describe "GET 'index' returns correct mailbox box" do
  before :each do
    @user = User.where(:user_name => 'test').where(:email => 'test@test.com').first_or_create
    @mailbox = @user.mailbox
  end

  it "#index returns inbox when box = 'inbox'" do
    mock_model User
    User.stub_chain(:where, :where).and_return(@user)
    controller.index.should == @mailbox.inbox
  end
end
¿Fue útil?

Solución

Filters and callbacks are hard to test and debug. Avoid them when possible.

In this case I don't think your before_filter is necessary, thus no need to test it. The better home for the methods is model.

Check my refacoring:

class User < ActiveRecord::Base
  delegate :inbox, :sentbox, :trash, to: :mailbox
end

class ConversationsController < ::ApplicationController
  def index
    @conversations = current_user.send get_box
  end

  private
  def get_box
    # your code
  end
end

That's all. Should be enough.

You can then test regularly.

Otros consejos

First of all, read the oficial documentation for rails testing: using data for testing and passing parameters to controlers is explained there.

To generate data for your tests you can:

  1. fill your test database with some mailbox and users using rails fixtures or use something like factory girl

  2. use mock objects to fake data. I personally use the mocha gem but there are others

I tend to use a combination of both, prefering mock objects when possible and falling back to factory girl when mocking needs too much code.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top