Why is my rake task running twice in my test?
Asked Answered
P

4

8

I have a rake task test that I setup following the only examples I could find online.

It looks like this:

require 'test_helper'
require 'minitest/mock'
require 'rake'

class TestScrapeWelcome < ActiveSupport::TestCase
  def setup
    Rake.application.init
    Rake.application.load_rakefile

    @task = Rake::Task['scrape:scrape']
    @task.reenable
  end

  def teardown
    Rake::Task.clear
  end

  test "scraping text and sending to elasticsearch" do
    mocked_client = Minitest::Mock.new
    get_fixtures.each_with_index do |arg,i|
      mocked_client.expect :index, :return_value, [index: "test", type: 'welcome', id: i, body: arg]
    end
    Elasticsearch::Model.stub :client, mocked_client do
      @task.invoke
    end
    assert mocked_client.verify
  end

  private

  def get_fixtures
    (0..11).map { |i|
      File.read("test/fixtures/scrape/index_#{i}.json")
    }
  end

end

But after the task runs once it starts running again without me doing anything (puts prints before and after @task.invoke show that the task is only run the once).

Putty answered 25/7, 2015 at 2:35 Comment(0)
P
13

Turns out that rake is already required and initialized when the test runs so all of the following lines need to be removed or the task gets defined twice and runs twice even if you only invoke it once.

require 'minitest/mock'
require 'rake'
...
Rake.application.init
Rake.application.load_rakefile
Putty answered 25/7, 2015 at 2:35 Comment(0)
V
5

Updated answer for rails 5.1 (using minitest):

I found I needed the following to load tasks once and only once:

MyAppName::Application.load_tasks if Rake::Task.tasks.empty?

Alternatively add MyAppName::Application.load_tasks to your test_helper, if you don't mind tasks being loaded even when running individual tests that don't need them.

(Replace MyAppName with your application name)

Veneaux answered 6/8, 2017 at 10:3 Comment(5)
If you have any gems that add rake tasks, this answer will cause your application tasks not to load, because Rake::Task.tasks won't be empty at this point.Tappet
The gems I use all need to be explicitly added to rake, so this works for me. What gems have you found automatically add their rake tasks into the application? And in that case how would you solve the problem?Veneaux
Grins with Jared - I understand. I still have a client on Rails 2.3.18 LTS (and they probably wont ever upgrade past that because they don't have the budget to update whilst there is a free LTS version). Unfortunately the later LTS versions are not free.Veneaux
I deleted previous comment. @Veneaux is referring to it as I wrote that I still use Rails 3.2 and this solution was a fix for me even with that old Rails. Unfortunately it turned out that none other tasks are working besides rake test, so let's say rake db:migrate was failing as rake didn't know how to build it. But I will fiddle with it more as it is good trace, and I'll post my findings later.Nappie
OK, for me, in Rails 3.2 tasks were not empty at that point so it never worked, and only existing tasks were loaded, which were :default and :test. That means that no other task would get loaded. I will now post my solution that's actually just a version of this one.Nappie
N
4

I've tried @iheggie answer but it worked in a way that indeed tests were run once but any other task was breaking with Don't know how to build task '<task_name_like_db_migrate>'.

I'm on Rails 3.2 still. It turned out that there were couple tasks loaded beforehand so the Rake::Task.tasks.empty? was never true and all other useful tasks were not loaded. I've fiddled with it and this version of it works for me right now:

Rake::Task.clear if Rails.env.test?
MyAppName::Application.load_tasks

Hope this helps anyone.

Nappie answered 18/9, 2019 at 14:9 Comment(1)
Rake::Task.clear works for me!Etherege
S
0

A solution that works for testing the tasks of a Gem that has been made a Railtie so it can add tasks to the Rails app:

Don't define the Railtie in test mode when you're also defining a Rails::Application class in spec_helper.rb (which allows your tests to call Rails.application.load_tasks). Otherwise the Rake file will be loaded once as a Railtie and once as an Engine:

class Railtie < Rails::Railtie
  rake_tasks do
    load 'tasks/mygem.rake'
  end
end unless Rails.env.test? # Without this condition tasks under test are run twice

Another solution would be to put a condition in the Rake file to skip the task definitions if the file has already been loaded.

Strahan answered 5/11, 2017 at 0:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.