I use mini-test for testing framework. I use omniauth gem for authentication. I use simplecov for code coverage. I run my tests using "bundle exec rake" or "rake minitest:controllers". I give an example for controllers. When I run rake minitest:controllers, controllers code coverage becomes 100%. But, when I run bundle exec rake, controllers code coverage become 60%.
SessionsController.rb code:
class SessionsController < ApplicationController
def create
auth = request.env["omniauth.auth"]
person=Person.find_by_provider_and_uid(auth.provider,auth.uid) || Person.create_with_omniauth(auth)
redirect_to root_path
end
end
SessionsController_test.rb
require "minitest_helper"
describe SessionsController do
before do
request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:identity]
#person = Fabricate.build(:person)
end
it "should create authentication" do
assert_difference('Person.count') do
post :create, :provider => "identity"
end
assert_redirected_to root_path #person
end
end
I wonder that if I miss one point on writing test. I wait your ideas. Thanks in advance.
EDIT
minitest_helper.rb
require 'simplecov'
Simplecov.start
ENV["RAILS_ENV"] = "test"
require File.expand_path('../../config/environment', __FILE__)
require "minitest/autorun"
require "minitest/rails"
require "minitest/pride"
require 'database_cleaner'
require "minitest/rails/capybara"
require "minitest-mongoid"
DatabaseCleaner[:mongoid].strategy = :truncation
#OmniAuth.config.test_mode = true
OmniAuth.config.add_mock(:identity, {
:uid => '12345'
})
class MiniTest::Spec
before :each do
DatabaseCleaner.start
end
after :each do
DatabaseCleaner.clean
end
end
According to Simplecov's documentation, you just have to add theses lines in top of your test/test_helper.rb:
# test/test_helper.rb
require 'simplecov'
SimpleCov.start
# ...
Also do not forget to install simplecov gem in test group:
# Gemfile
# ...
group :test do
gem 'simplecov'
end
And that's it.
Rails 6: I encountered some issues with Rails 6 and tests paralelization so you may deactivate it in test/test_helper.rb:
# test/test_helper.rb
# ...
class ActiveSupport::TestCase
# ...
# parallelize(workers: 2)
end
It's hard to tell with no more information.
First of all try rake minitest:all and update your question with the result.
Please try following in case the former test did not conclude positively:
namespace :test do
task :coverage do
require 'simplecov'
SimpleCov.start 'rails' # feel free to pass block
Rake::Task["test"].execute
end
end
Let us know and we can edit or update the answer.
Minitest is known to have had some issues with it. I believe it was still work in progress, not sure where they stand now. It is not you, it's minitest. That workaround helped in some cases, maybe it helps you too.
Related
I'm very new to TDD, and have opted to go with the above mentioned Gems. I think I have set it up correctly as I can run my tests. I can't, however, figure out how to populate my test database from db/seeds.rb. When I invoke
rake db:seed RAILS_ENV=test
in the terminal, I can see the rows created in the database through PGAdmin. However, when I run my tests with the following
rake minitest:all
the database ends up being blank afterwards, and in the test when I save a screenshot, the items from the database does not appear in the frontend as it does when I'm in dev.
My test_helper.rb contains the following.
ENV["RAILS_ENV"] = "test"
require File.expand_path("../../config/environment", __FILE__)
require "rails/test_help"
require "minitest/rails"
require 'minitest/rails/capybara'
require 'minitest/focus'
require 'minitest/colorize'
Capybara.javascript_driver = :webkit
class ActiveSupport::TestCase
fixtures :all
DatabaseCleaner.strategy = :transaction
class MiniTest::Spec
before :each do
Rake::Task["db:seed"].invoke
DatabaseCleaner.start
end
after :each do
DatabaseCleaner.clean
end
end
end
And for some extra background, my db/seeds.rb file (which works when seeded from manually using rake)
ProgramIndustry.delete_all
ProgramIndustry.create([
{ name: 'Accounting and finance'},
{ name: 'Banking'},
{ name: 'Construction'},
{ name: 'Education'}
])
Why would the database not be populated with seeds.rb when the tests start?
Your database is blank because you are using DatabaseCleaner, which removes the data from the database. I assume this is what you want your test_helper.rb file to look like:
ENV["RAILS_ENV"] = "test"
require File.expand_path("../../config/environment", __FILE__)
require "rails/test_help"
require "minitest/rails"
require 'minitest/rails/capybara'
require 'minitest/focus'
require 'minitest/colorize'
Capybara.javascript_driver = :webkit
class ActiveSupport::TestCase
fixtures :all
DatabaseCleaner.strategy = :transaction
before do
DatabaseCleaner.start
Rake::Task["db:seed"].invoke # seed after starting
end
after do
DatabaseCleaner.clean
end
end
I don't know about invoking the db:seed task from the before hook, that seems kinda suspect. But I don't use DatabaseCleaner, as I prefer to use fixtures and the transactions supported by ActiveSupport::TestCase.
I don't know why you are using DatabaseCleaner, but seeing as you are using RSpec syntax in Minitest, I'm assuming you are just trying things until they work. Might I suggest the dropping DatabaseCleaner and put all your test data in fixtures and using the following to manage the database transactions across threads:
ENV["RAILS_ENV"] = "test"
require File.expand_path("../../config/environment", __FILE__)
require "rails/test_help"
require "minitest/rails"
require 'minitest/rails/capybara'
require 'minitest/focus'
require 'minitest/colorize'
class ActiveSupport::TestCase
fixtures :all
end
# Capybara driver
Capybara.javascript_driver = :webkit
# Make all database transactions use the same thread
ActiveRecord::ConnectionAdapters::ConnectionPool.class_eval do
def current_connection_id
Thread.main.object_id
end
end
And if you have issues with that, consider this variation:
ENV["RAILS_ENV"] = "test"
require File.expand_path("../../config/environment", __FILE__)
require "rails/test_help"
require "minitest/rails"
require 'minitest/rails/capybara'
require 'minitest/focus'
require 'minitest/colorize'
class ActiveSupport::TestCase
fixtures :all
end
# Capybara driver
Capybara.javascript_driver = :webkit
# Make all database transactions use the same thread
class ActiveRecord::Base
mattr_accessor :shared_connection
##shared_connection = nil
def self.connection
##shared_connection || retrieve_connection
end
end
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
Does anyone know how to test a controller of gem in the app using the gem with rspec? I have tried http://codingdaily.wordpress.com/2011/01/14/test-a-gem-with-the-rails-3-stack/ and http://say26.com/rspec-testing-controllers-outside-of-a-rails-application without success.
I have a controller in a gem like this:
module mygem
class PostsController < ::ApplicationController
def index
#posts = Posts.find(:all)
#other_var = 10
end
end
end
And I would like to have a test in my app like spec/controllers/posts_controller_spec.rb
describe PostsController do
describe "index" do
it "has posts" do
get :index
assigns(:posts).should_not be_nil
end
it "has other var" do
get :index
assert_equal(10, assigns(:other_var))
end
end
end
And my spec_helper.rb
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
RSpec.configure do |config|
end
I know rspec isn't really meant for this, and ideas or alternatives would be helpful too.
A gem is a gem, an app is an app. They are different stuff.
I don't think it's a good practice to mix testing of gem into the app.
Normally you don't need to test a gem because they are usually well tested. If you really want to do that or the gem is lack of test, fork the gem and pull it in local, then open its test files and add yours. Then you can push it back to improve this gem or end up your own version of gem.
If you are writing your own gem, put the tests in gem but not app.
If you want to test some functionalities the gem added to your app, you can test the integrated effect, but don't need unit testing.
Ok I feel dumb now, I just had to add the gem namespace to the controllers. so
describe PostsController do
...
end
becomes
describe mygem::PostsController do
...
end
I'm receiving the following error when I try to run my request specs:
POST :: /users/:id/authentications request::successful request#test_0001_Adds an authentication record to a user:
NoMethodError: undefined method `post' for #<#<Class:0x007fa607163028>:0x007fa6070012c0>
test/requests/authentications_test.rb:9:in `block (3 levels) in <main>'
Here's the test itself:
require "minitest_helper"
describe "POST :: /users/:id/authentications request" do
describe "successful request" do
it "Adds an authentication record to a user" do
user = create_user
post user_authentications_path(user)
response.status.must_equal "200"
end
end
end
Here's the minitest_helper.rb file:
ENV["RAILS_ENV"] = "test"
require File.expand_path("../../config/environment", __FILE__)
require "rails/test_help"
require "minitest/autorun"
require "minitest/rails"
require "minitest/rails/capybara"
Dir[Rails.root.join("test/support/**/*.rb")].each {|f| require f}
class ActiveSupport::TestCase
end
# database cleaner
DatabaseCleaner.strategy = :transaction
class MiniTest::Spec
before :each do
DatabaseCleaner.start
end
after :each do
DatabaseCleaner.clean
end
end
class RequestTest < MiniTest::Spec
include Rails.application.routes.url_helpers
register_spec_type(/request$/, self)
end
Relevant versions of things:
Rails: 3.2.13
minitest-rails: 0.9.2
minitest-rails-capybara: 0.9.0
It really doesn't make sense that I can't call post. It looks like every other example out the web can do it just fine.
Any help with this is greatly appreciated.
You have a lot going on in your test helper. It seems that you have copied several different approaches to running minitest in your rails tests. I suggest the following:
Remove the following from your test helper:
# database cleaner
DatabaseCleaner.strategy = :transaction
class MiniTest::Spec
before :each do
DatabaseCleaner.start
end
after :each do
DatabaseCleaner.clean
end
end
class RequestTest < MiniTest::Spec
include Rails.application.routes.url_helpers
register_spec_type(/request$/, self)
end
Add the following to your test helper:
class ActionDispatch::IntegrationTest
# Register "request" tests to be handled by IntegrationTest
register_spec_type(/Request( ?Test)?\z/i, self)
end
I'm using capybara with minitest on Rails 2.3.14. Like most applications, this one also requires login to do anything inside the site. I'd like to be able to login once per test-suite and use that session throughout all tests that are run. How do I refactor that to the minitest_helper? Right now my helper looks something like this:
#!/usr/bin/env ruby
ENV['RAILS_ENV'] = 'test'
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
gem 'minitest'
gem 'capybara_minitest_spec'
require 'minitest/unit'
require 'minitest/spec'
require 'minitest/mock'
require 'minitest/autorun'
require 'capybara/rails'
require 'factory_girl'
FactoryGirl.find_definitions
class MiniTest::Spec
include FactoryGirl::Syntax::Methods
include Capybara::DSL
include ActionController::URLWriter
before(:each) do
# .. misc global setup stuff, db cleanup, etc.
end
after(:each) do
# .. more misc stuff
end
end
thanks.
Here’s an example of multiple sessions and custom DSL in an integration test
require 'test_helper'
class UserFlowsTest < ActionDispatch::IntegrationTest
fixtures :users
test "login and browse site" do
# User avs logs in
avs = login(:avs)
# User guest logs in
guest = login(:guest)
# Both are now available in different sessions
assert_equal 'Welcome avs!', avs.flash[:notice]
assert_equal 'Welcome guest!', guest.flash[:notice]
# User avs can browse site
avs.browses_site
# User guest can browse site as well
guest.browses_site
# Continue with other assertions
end
private
module CustomDsl
def browses_site
get "/products/all"
assert_response :success
assert assigns(:products)
end
end
def login(user)
open_session do |sess|
sess.extend(CustomDsl)
u = users(user)
sess.https!
sess.post "/login", :username => u.username, :password => u.password
assert_equal '/welcome', path
sess.https!(false)
end
end
end
Source : http://guides.rubyonrails.org/testing.html#helpers-available-for-integration-tests
I recently switched a very simple rails app from rspec to minitest. I also use capybara and factory_girl.
I have 3 separate integration test files, all of which involve logging the user in using something along the lines of:
before(:each) do
user = Factory(:user)
visit login_path
fill_in "Email", :with => user.email
fill_in "Password", :with => user.password
click_button "Log in"
end
After I switched to minitest, it seems as if the sessions ceased to tear down after each test. For instance, I would test login using the above code in a test file named "users_integration_test.rb" and when it begins running another test file, say "sessions_integration_test.rb", the user is already logged in before I can log in again using the above code.
My question is: Is this an intentional difference between rspec and minitest, and I simply need to logout the user after each test? Or did I make a mistake setting up minitest?
I am using the same minitest_helper file as in the Minitest Railscast.
I don't know the difference but below code may work.
ENV["RAILS_ENV"] = "test"
require File.expand_path("../../config/environment", __FILE__)
require "minitest/autorun"
require "capybara/rails"
require "active_support/testing/setup_and_teardown"
class IntegrationTest < MiniTest::Spec
include Rails.application.routes.url_helpers
include Capybara::DSL
after do
reset_session!
end
register_spec_type(/integration$/, self)
end
class HelperTest < MiniTest::Spec
include ActiveSupport::Testing::SetupAndTeardown
include ActionView::TestCase::Behavior
register_spec_type(/Helper$/, self)
end
I got it to tear down correctly with this. Hope it helps!
Mr. Maeshima's answer may very well work too. I have not tried.
ENV["RAILS_ENV"] = "test"
require File.expand_path("../../config/environment", __FILE__)
require "minitest/autorun"
require "capybara/rails"
require "active_support/testing/setup_and_teardown"
Dir[Rails.root.join("test/support/**/*.rb")].each {|f| require f}
DatabaseCleaner.strategy = :truncation
class IntegrationTest < MiniTest::Spec
include Rails.application.routes.url_helpers
include Capybara::DSL
register_spec_type(/integration$/, self)
Capybara.javascript_driver = :selenium
after do
DatabaseCleaner.clean # Truncate the database
Capybara.reset_sessions! # Forget the (simulated) browser state
Capybara.use_default_driver # Revert Capybara.current_driver to Capybara.default_driver
end
end
class HelperTest < MiniTest::Spec
include ActiveSupport::Testing::SetupAndTeardown
include ActionView::TestCase::Behavior
register_spec_type(/Helper$/, self)
end