metaskills / minitest-spec-rails

:bento: Make Rails Use MiniTest::Spec!

Home Page:http://github.com/metaskills/minitest-spec-rails

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot use with database_cleaner gem

leebrooks0 opened this issue · comments

I am trying to use your gem with database_cleaner. In my testhelper.rb I have the following:

require 'database_cleaner'
DatabaseCleaner.strategy = :truncation
MiniTest::TestCase.add_setup_hook { DatabaseCleaner.start }
MiniTest::TestCase.add_teardown_hook { DatabaseCleaner.clean }

The hooks are necessary as if you use before and after like they do here:
https://github.com/bmabey/database_cleaner
you will override them when you use before and after blocks in your test.

I keep getting this message though:

rake aborted!
NameError: uninitialized constant Minitest::TestCase
/home/lee/Code/mobifit/test/test_helper.rb:47:in `<top (required)>'
/home/lee/.rvm/gems/ruby-2.1.1/gems/railties-4.1.0.rc2/lib/rails/test_unit/sub_test_task.rb:114:in `block (3 levels) in define'
/home/lee/.rvm/gems/ruby-2.1.1/gems/railties-4.1.0.rc2/lib/rails/test_unit/sub_test_task.rb:114:in `each'
/home/lee/.rvm/gems/ruby-2.1.1/gems/railties-4.1.0.rc2/lib/rails/test_unit/sub_test_task.rb:114:in `block (2 levels) in define'
/home/lee/.rvm/gems/ruby-2.1.1/gems/railties-4.1.0.rc2/lib/rails/test_unit/sub_test_task.rb:113:in `each'
/home/lee/.rvm/gems/ruby-2.1.1/gems/railties-4.1.0.rc2/lib/rails/test_unit/sub_test_task.rb:113:in `block in define'
/home/lee/.rvm/gems/ruby-2.1.1/gems/railties-4.1.0.rc2/lib/rails/test_unit/sub_test_task.rb:31:in `create_and_run_single_test'
/home/lee/.rvm/gems/ruby-2.1.1/gems/railties-4.1.0.rc2/lib/rails/test_unit/sub_test_task.rb:17:in `invoke_rake_task'
/home/lee/.rvm/gems/ruby-2.1.1/gems/railties-4.1.0.rc2/lib/rails/test_unit/testing.rake:8:in `block in <top (required)>'
-e:1:in `<main>'
Tasks: TOP => test:single
(See full trace by running task with --trace)

Googling yields nothing, so I don't know where the problem lies.

The examples on the database cleaner repo look outdated and/or just wrong. There is no such things as :each in MiniTest. https://github.com/bmabey/database_cleaner#minitest-example

I think you are adding too much technical details here. May I suggest the following in your test_helper.rb file.

ENV["RAILS_ENV"] ||= "test"
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'

class ActiveSupport::TestCase
  ActiveRecord::Migration.check_pending!
  DatabaseCleaner.strategy = :truncation
  before { DatabaseCleaner.start }
  after  { DatabaseCleaner.clean } 
end

First, if DB cleaner is in your test group, it is required for you. No need to do it again. Second, you are trying to hook into MiniTest, that is too low level, you want to hook into ActiveSupport::Test case and that is why I have these examples shown this way. MiniTest does not have a notion of before/after stacks. This gem extends MiniTest (for AS::TC) to maintain the Rails setup/teardown callback style that allows you to push multiple before/after blocks.

Also, for the record, I high recommend using a clean DB in Rails. Using factories is awesome. But so are DB transactions with fixtures. May I suggest the following reading/tools on the topic.

FYI, I will have some patches in the named_seeds gem today for Rails 4.1 compatibility. Also, 4.1.0 is out as of yesterday too.

Thanks for the advice, I removed require 'database_cleaner, and used the snippet you suggested (except in Rails 4.1 the test db is automatically maintained, http://edgeguides.rubyonrails.org/4_1_release_notes.html#railties-notable-changes), and it works correctly.

I read through the links you gave, and they were very interesting, thank you, I am now using minitest-focus (from holy_grail_harness - have been needing something just like that...), named seeds is also looking very useful, my app has users with certain roles etc that are constantly inserted into the database for a large amount of tests.

Truncation as your second link pointed out is very, very slow, my test suite just slowed down about 10 fold, purely due to truncating after each test. However, I am using Devise, and DeviseAsync to send the emails with DelayedJob, but DeviseAync does not send the emails until after commit, and that can cause problems in your integration tests (as in full stack, not what rails calls an integration tests), see https://github.com/mhfs/devise-async#testing.

I think the best idea is to scrap DeviseAsync, and just override the relevant Devise methods to send, the mails with DelayedJob as suggested here: http://stackoverflow.com/questions/13531515/disable-devise-confirmable-mails

Turns out, my test.rb file was missing this:

# You need to set up the default url options for the Devise mailer in each environment
   config.action_mailer.default_url_options = { host: 'localhost:3000' } 

that was why it wasn't sending, DeviseAsync then works correctly with transactional tests, never mind what the readme says.

Awesome and congrats. Thanks for checking out my other info and sharing your details too.

Trying to follow your example, I get thrown NoMethodError: undefined methodbefore' for ActiveSupport::TestCase:Class`

My test_helper.rb:

ENV['RAILS_ENV'] = 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'

require 'minitest/pride' # awesome colorful output
require 'minitest/reporters' # fancier output format
Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new

# Requires supporting ruby files with custom matchers and macros, etc,
# in test/support/ and its subdirectories.
Dir[Rails.root.join('test/support/**/*.rb')].each{ |f| require f }
RedSteel::Application.reload_routes!

class ActiveSupport::TestCase
  ActiveRecord::Migration.check_pending!
  DatabaseCleaner.strategy = :transaction
  before :each do
    DatabaseCleaner.start
    DeferredGarbageCollection.start
  end

  after :each do
    DatabaseCleaner.clean
    DeferredGarbageCollection.reconsider
  end
end

class ActionController::TestCase
  include Devise::TestHelpers
end

I should add as well that I have some custom rake tasks setup for *_spec files:

namespace :spec do
  Rails::TestTask.new(:all) do |t|
    t.libs << 'test'
    t.pattern = 'test/**/*_spec.rb'
  end

  namespace :all do
    desc 'Run tests quickly, but also reset db'
    task :db => %w[db:test:prepare spec:all]
  end
end
Rake::Task[:test].enhance{ Rake::Task['spec:all'].invoke }

rake test works as expect, but rake spec:all provides the error above.

@elsom25 :each is ignored http://bfts.rubyforge.org/minitest/MiniTest/Spec.html#method-c-before, although that is not the answer to your question. Also, why are you using DatabaseCleaner if you need transactional tests, as Rails already gives you transactional tests?

oh sorry, that was a mistype, though changing that naturally doesn't remove the error.

commented

before and after have been replaced with setup and teardown for anyone who is experiencing the NoMethodError: undefined method 'before' for ActiveSupport::TestCase:Class error.

The following works in Rails 5:

class ActiveSupport::TestCase
  include FactoryGirl::Syntax::Methods

  ActiveRecord::Migration.check_pending!
  DatabaseCleaner.strategy = :truncation
  DatabaseCleaner.logger = Rails.logger
  setup { DatabaseCleaner.start }
  teardown { DatabaseCleaner.clean }
end

@dmvt The setup and teardown blocks have been in Rails for as long as I can remember. Rails has always made those methods use the callback chain so you can stack them up. This gem has always delegated to those methods so MiniTest's before/after syntax follows that practice. More details here:

Lastly, I have never had an issue using this gem with DatabaseCleaner. Hope that info is helpful if anyone is having issues. Please share details if you are.