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
Related
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.
I'd like to be able to call login_as_admin and login_as_customer at any point in any spec file.
I have a directory full of integration specs:
/spec/features/area_spec.rb
/spec/features/assignment_spec.rb
/spec/features/etc…
Each of which starts with:
require 'spec_helper'
require 'rspec_macros'
I also have /spec/spec_help.rb, which includes:
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require File.dirname(__FILE__) + "/rspec_macros"
And I have /spec/rspec_macros.rb, which includes:
module RspecMacros
def login_as_admin
etc…
end
def login_as_customer
etc…
end
end
Why, then, do I get the following error at the Rspec command line?
Failure/Error: login_as_customer
NameError:
undefined local variable or method `login_as_customer' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_2:0x007fd99f471f50>
I believe you either need to make these functions in spec helper or include the modules in your tests.
To include the modules you can do something like this:
module RspecMacros
extend ActiveSupport::Concern
included do
def login_as_customer
...
end
end
end
require 'rspec_macros'
describe MyCoolTest do
include RspecMacros
end
You may find it easier to just make them functions in spec helper. You can just add:
def login_as_customer
....
end
to the end of spec_helper.rb
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
When running the rspec I get:
C:/www/kill/spec/games_controller_spec.rb:4:in block in <top
(required)>': undefined local variable or methodrender_views'
games_controller_spec.rb
require 'spec_helper'
describe GamesController, "creating a new game" do
render_views
fixtures :games
it "should redirect to index with a notice on successful save" do
Game.any_instance.stubs(:valid?).returns(true)
post 'create'
assigns[:game].should_not be_new_record
flash[:notice].should_not be_nil
response.should redirect_to(menu_items_path)
end
end
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|
# == Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
#config.mock_with :rspec
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = true
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
end
gems:
C:/Ruby192/lib/ruby/gems/1.9.1/gems/rspec-2.7.0
C:/Ruby192/lib/ruby/gems/1.9.1/gems/mocha-0.10.0
Your controller specs should be in the spec/controllers/ folder. However, you may want for some reason to have some other files that run controller specs (for example, I'm testing markup validation in a separate test file).
You can do this :
describe GamesController, "creating a new game", :type => :controller do
And this should do the trick !
You should place your controller specs inside a spec/controllers directory. RSpec is including these methods based on this, AFAIK.
In my case my test was already in spec/controllers/. I needed to add config.infer_spec_type_from_file_location! inside the RSpec.configure do |config| loop in spec_helper.rb. I had updated rspec from 2.x to 3.x without realizing it, and that config is needed for controller tests from 3.x.
If you test the views, RSpec have the spec/requests directory for that, it will render views by default. (See the doc)
this problem may be caused by your Gem rspec-rails version. downgrade it back to 2.x solved my problem:
# edit your Gemfile
gem "rspec-rails", "2.14.2"
I'm creating a gem that will generate a controller for the Rails app that will use it. It's been a trial and error process for me when trying to test a controller. When testing models, it's been pretty easy, but when testing controllers, ActionController::TestUnit is not included (as described here). I've tried requiring it, and all similar sounding stuff in Rails but it hasn't worked.
What would I need to require in the spec_helper to get the test to work?
Thanks!
Here's an example of a working standalone Test::Unit test with a simple controller under test included.. Maybe there's some parts here that you need to transfer over to your rspec code.
require 'rubygems'
require 'test/unit'
require 'active_support'
require 'active_support/test_case'
require 'action_controller'
require 'action_controller/test_process'
class UnderTestController < ActionController::Base
def index
render :text => 'OK'
end
end
ActionController::Routing::Routes.draw {|map| map.resources :under_test }
class MyTest < ActionController::TestCase
def setup
#controller = UnderTestController.new
#request = ActionController::TestRequest.new
#response = ActionController::TestResponse.new
end
test "should succeed" do
get :index
assert_response :success
end
end