Пересмешивание / заглушка метода Application Controller с помощью Mocha (Using Shoulda, Rails 3) - PullRequest
3 голосов
/ 05 октября 2010

При написании функциональных тестов для контроллера я столкнулся со сценарием, в котором у меня есть before_filter, запрашивающий некоторую информацию из базы данных, которая требуется для одного из моих тестов. Я использую Factory_girl для генерации тестовых данных, но я хочу избежать попадания в базу данных, когда она явно не нужна. Я также хотел бы избежать тестирования моего метода before_filter здесь (я планирую проверить его в отдельном тесте). Как я понимаю, издевательство / окурки - это способ сделать это.

Мой вопрос заключается в том, как лучше всего смоделировать / заглушить этот метод в этом сценарии.

Метод My before filter ищет сайт в БД на основе субдомена, найденного в URL, и устанавливает переменную экземпляра для использования в контроллере:


#application_controller.rb

def load_site_from_subdomain
  @site = Site.first(:conditions => { :subdomain => request.subdomain })
end

Мой контроллер, который использует этот метод в качестве before_filter:


# pages_controller.rb

before_filter :load_site_from_subdomain

def show
  @page = @site.pages.find_by_id_or_slug(params[:id]).first
  respond_to do |format|
    format.html { render_themed_template }
    format.xml  { render :xml => @page }
  end
end

Как видите, он зависит от переменной @site, которую нужно установить (с помощью before_filter). Во время тестирования, однако, я хотел бы, чтобы тест предполагал, что @site был установлен, и что у него есть по крайней мере 1 связанная страница (найденная @site.pages). Затем я бы хотел проверить свой метод load_site_from_subdomain.

Вот то, что у меня есть в моем тесте (с использованием Следует и Мокко):


context "a GET request to the #show action" do

  setup do
    @page = Factory(:page)
    @site = Factory.build(:site)

    # stub out the @page.site method so it doesn't go 
    # looking in the db for the site record, this is
    # used in this test to add a subdomain to the URL
    # when requesting the page
    @page.stubs(:site).returns(@site)

    # this is where I think I should stub the load_site_from_subdomain
    # method, so the @site variable will still be set
    # in the controller. I'm just not sure how to do that.
    @controller.stubs(:load_site_from_subdomain).returns(@site)

    @request.host = "#{ @page.site.subdomain }.example.com"
    get :show, :id => @page.id
  end

  should assign_to(:site)
  should assign_to(:page)
  should respond_with(:success)

end

Это оставляет меня с ошибкой в ​​моих результатах теста, говорящей мне, что @site - ноль.

Я чувствую, что поступаю неправильно. Я знаю, что было бы просто просто создать Factory.создать сайт таким образом, чтобы он существовал в БД, но, как я сказал ранее, я хотел бы уменьшить использование БД, чтобы помочь ускорить мои тесты.

Ответы [ 2 ]

1 голос
/ 05 октября 2010

Попробуйте заглушить 'Site.first', так как это настройка переменной @site, которую вам нужно заглушить, а не возвращенная переменная из before_filter.

0 голосов
/ 25 октября 2012

Причина, по которой ваш @site равен nil, потому что ваш load_site_from_subdomain выполняет присвоение значения для @site - он не возвращает никакого значения, следовательно, ваша заглушка для load_site_from_subdomain просто не присваивает значение@site.Для этого есть два обходных пути:

Первый способ:

Измените load_site_from_subdomain, чтобы просто сделать возвращаемое значение:

def load_site_from_subdomain
  Site.first(:conditions => { :subdomain => request.subdomain })
end

а затем удалите before_filter :load_site_from_subdomain и измените show на:

def show
  @site = load_site_from_subdomain
  @page = @site.pages.find_by_id_or_slug(params[:id]).first
  respond_to do |format|
    format.html { render_themed_template }
    format.xml  { render :xml => @page }
  end
end

, а затем выполните проверку в тесте:

@controller.stubs(:load_site_from_subdomain).returns(@site)

, которая гарантирует, что наша @site заглушкакосвенно через load_site_from_subdomain

Второй способ

Чтобы заглушить Site.first, мне не очень нравится этот подход, так как в функциональном тестировании нас не особо волнуеткак модель извлекается, но поведение respond.В любом случае, если вы хотите пойти по этому пути, вы можете заглушить его в своем тесте:

Site.stubs(:first).returns(@site)
...