I'm trying out 'shoulda' on top of rspec (rails 3) with the following spec:
require 'spec_helper'
describe Article do
should "be true" do
assert true
end
end
and it fails with
/Users/jeppe/.rvm/gems/ruby-1.8.7-p302/gems/rspec-expectations-2.0.0.beta.20/lib/rspec/expectations/handler.rb:11:in `handle_matcher': undefined method `matches?' for "be true":String (NoMethodError)
Now my tests will run just fine when I do both
require 'spec_helper'
describe Article do
it "should be true" do
assert true
end
end
and
require 'spec_helper'
describe Article do
it { should belong_to :issue }
it { should have_and_belong_to_many :pages }
it { should have_many :tasks }
end
where the last uses Shoulda::ActiveRecord::Matchers, so to my knowledge shoulda is loaded allright.
Any suggestions?
In RSpec should is an RSpec method used to trigger a matcher - it is not Shouldas context block. For that, you use RSpecs own describe.
should "be true" do
assert true
end
is Shoulda's Test::Unit based syntax, which shouldn't work in RSpec examples (I guess?). Just use your second example, which has the same effect and the right syntax.
Related
I'm doing a test using RSPEC, and used Sidekiq for background jobs.
Since, there's no generator for workers in rspec, not sure what to use.
https://relishapp.com/rspec/rspec-rails/docs/generators
require 'spec_helper'
RSpec.describe TestWorker, type: ? do # ex. :worker :sidekiq ...
describe "TestWorker" do
it "" do
....
end
end
end
bundle exec rspec spec/workers/test_worker_spec.rb
Doing like below, i'm getting: uninitialized constant TestWorker
require 'spec_helper'
describe TestWorker do
it "" do
....
end
end
As i tried, gem rspec-sidekiq
https://github.com/philostler/rspec-sidekiq
Can someone provide a sample template for testing app/workers/ in Rspec.
Thanks.
I have not used the rspec-sidekiq gem, however, here is an example of how I am checking for Background jobs which uses sidekiq
# app/spec/workers/demo_worker_spec.rb
require 'rails_helper'
require 'sidekiq/testing'
Sidekiq::Testing.fake!
RSpec.describe DemoWorker, type: :worker do
describe "Sidekiq Worker" do
let (:demo) { FactoryGirl.create(:demo) }
it "should respond to #perform" do
expect(DemoWorker.new).to respond_to(:perform)
end
describe "Demo" do
before do
Sidekiq::Extensions.enable_delay!
Sidekiq::Worker.clear_all
end
it "should enqueue a Email and SMS job" do
assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
Mailer.delay.demo_request(demo.id)
assert_equal 1, Sidekiq::Extensions::DelayedMailer.jobs.size
end
end
end
end
As of I'm checking, if the instance responds to perform.
Then, I'm asserting before and after the job is scheduled.
You might sometimes want to test more than just the fact that the worker has been enqueud or not.
While it is better to decouple complex stuff that could happen in a worker's perform block, it can be tested as a standard class :
it { expect { MyWorker.new.perform }.to change { ...expectations... } }
or
it do
MyWorker.new.perform
... expectations ..
end
I'm using RSpec with FactoryGirl within a Ruby on Rails environment for testing.
I want to specify my factories as follows:
factory :user do
role # stub
factory :resident do
association :role, factory: :resident_role
end
factory :admin do
association :role, factory: :admin_role
end
end
And I'd like to do something like this in my spec:
require 'rails_helper'
RSpec.describe User, type: :model do
context "all users" do
# describe a user
# subject { build(:user) }
# it { is_expected.to be_something_or_do_something }
end
context "residents" do
# describe a resident
# subject { build(:resident) }
# it { is_expected.to be_something_or_do_something }
end
context "admins" do
# describe a admin
# subject { build(:admin) }
# it { is_expected.to be_something_or_do_something }
end
end
Can this be done by explicitly setting the subject? When I do, I keep getting duplicate roles errors.
If anyone has any advice or suggestion, it would be greatly appreciated!
But this causes the user_spec.rb to use the :user factory.
No, it does not. Assuming you configured FactoryGirl correctly, RSpec can use whatever factory you'd like "on demand" in any test file. Configuration-wise, in rails_helper.rb throw this in:
RSpec.configure do |config|
# ...
config.include FactoryGirl::Syntax::Methods
# ...
end
Then, in your spec file:
require 'rails_helper'
RSpec.describe User, type: :model do
context "all users" do
let(:user) { create(:user) }
it 'is a user' do
# Here `user` is going to be a user factory
expect(user.unit).not_to be_present
end
end
context "residents" do
let(:user) { create(:resident) }
it 'is a resident' do
# Here `user` is going to be a resident factory
expect(user.unit).to be_present
end
end
context "admins" do
let(:user) { create(:admin) }
it 'is an admin' do
# Here `user` is going to be an admin factory
expect(user.role).to be('admin_role')
end
end
end
In short, you can use create(<factory_name>) on any factory definition that exists in any one of these paths:
test/factories.rb
spec/factories.rb
test/factories/*.rb
spec/factories/*.rb
Note that if you haven't placed the config.include FactoryGirl::Syntax::Methods inside your RSpec.configure, you can still create any factory, by doing FactoryGirl.create(<factory_name>) instead of create(<factory_name>).
I don't think you would want to stop them from auto loading, and I'm not actually sure what your use case is for not allowing them to load?
RSpec automagically fetches the factory for a spec
Rspec loads all the factories into memory when your spec helper loads I believe. Because your using factory inheritence your just loading each of these into memory before your tests run, nothing is being called, no objects are being created or built. They are just ready to use in your tests.
Are you getting a specific error or is there some case I'm not seeing that you need?
I found the solution to my problems here: https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#associations
What I needed to use in my user factories was association :role, factory: :role, strategy: :build
I have a helper method that uses 'request' to determine the URL. However, rspec can't seem to find request. I thought request was available to all front-facing tests?
How can I account for the request method in my spec?
Helper Spec
require 'spec_helper'
describe ApplicationHelper do
describe "full_title" do
it "should include the page title" do
expect(full_title("help")).to include('help')
end
end
end
Helper methods
def full_title(page_title)
if staging? # causing the issue
base_title = "Staging"
else
base_title = "Company Name"
end
if page_title.empty?
"#{base_title} | Tag line "
else
"#{base_title} | #{page_title} "
end
end
def staging? # the request here seems to be the problem
request.original_url.include? "staging"
end
Rspec error
Failure/Error: expect(full_title("help")).to include('help')
NameError:
undefined local variable or method `request' for #<RSpec::ExampleGroups::ApplicationHelper_2::FullTitle:0x00000106260078>
Thanks in advance.
First off: request is only available in the controller tests (and even then only in the request specs I think), helper tests are really basic and isolated. Which is good. Your helper code should be really minimal and normally only work on the input it receives.
However this is pretty easily solvable by using stubbing.
So write something like
#note, OP needed to replace 'helper' with 'self'for Rails 4.0.0 and Rspec 3.0
require 'rails_helper'
describe ApplicationHelper do
describe "full_title" do
context "in staging" do
it "should include the page title" do
helper.should_receive(:staging?).and_return(true)
expect(full_title("help")).to include('help')
end
end
context "not in staging" do
it "should include the page title" do
helper.should_receive(:staging?).and_return(false)
expect(full_title("help")).to include('help')
end
end
end
end
Which is imho a very clear, and then you write separate tests for your staging? method:
describe "staging?" do
context "when in staging" do
it "returns true" do
helper.stub(:request) { OpenStruct.new(original_url: 'staging') }
expect( helper.staging? ).to be true
end
end
context "when not in staging" do
it "returns false" do
helper.stub(:request) { OpenStruct.new(original_url: 'development') }
expect(helper.staging?).to be false
end
end
end
end
Some small remarks: ruby default indentation is 2 spaces.
Secondly, your function now literally says return true if true, ideally it should be written like
def staging?
request.original_url.include? "staging"
end
I have the following RSpec test for my UserMailer class:
require "spec_helper"
describe UserMailer do
it "should send welcome emails" do
ActionMailer::Base.deliveries.should be_empty
user = Factory(:user)
UserMailer.welcome_email(user).deliver
ActionMailer::Base.deliveries.should_not be_empty
end
end
This test passed the first time, but failed the second time I ran it. After doing a little bit of debugging, it appears that the 1st test added an item to the ActionMailer::Base.deliveries array and that item never got cleared out. That causes the first line in the test to fail since the array is not empty.
What's the best way to clear out the ActionMailer::Base.deliveries array after an RSpec test?
RSpec.describe UserMailer do
before do
# ActionMailer::Base.deliveries is a regular array
ActionMailer::Base.deliveries = []
# or use ActionMailer::Base.deliveries.clear
end
it "sends welcome email" do
user = create(:user)
UserMailer.welcome_email(user).deliver_now
expect(ActionMailer::Base.deliveries).to be_present
end
end
You can clear the deliveries after each test quite easily, adding this into your spec_helper.rb.
RSpec.configure do |config|
config.before { ActionMailer::Base.deliveries.clear }
end
I'd suggest reading my article about the correct emails configuration in Rails where I talk also about testing them correctly.
As Andy Lindeman points out, clearing the deliveries is done automatically for mailer tests. However, for other types, simply add , :type => :mailer to the wrapping block to force the same behavior.
describe "tests that send emails", type: :mailer do
# some tests
end
I had a bunch of combined controller/view tests written with rspec. I added the Capybara gem and wrote some integrations tests which pass fine. The only problem is that now in all my controller tests, where I have
response.should have_selector("some selector")
rspec gives errors such as:
NoMethodError:
undefined method `has_selector?' for #<ActionController::TestResponse:0xa03e7ec>
when I run controller tests. I'm guessing that Capybara is being used in my controller tests and has overwritten some Rspec methods. How can I fix this?
# gemfile.rb
group :test do
gem 'rspec'
gem "capybara"
gem "launchy"
gem 'factory_girl_rails', '1.0'
end
# spec_helper.rb
RSpec.configure do |config|
config.include IntegrationSpecHelper, :type => :request
end
Here's an example of a failing test:
# spec/controllers/books_controller_spec.rb
require 'spec_helper'
describe BooksController do
render_views
it "should have the right page title" do
get :show, :id => #book.ean
response.should have_selector("title", :content => "Lexicase | " + #book.title)
end
end
and it's associated error:
1) BooksController GET 'show' should have the right page title
Failure/Error: response.should have_selector("title", :content => "Lexicase | " + #book.title)
NoMethodError:
undefined method `has_selector?' for #<ActionController::TestResponse:0xa8488c0>
# ./spec/controllers/books_controller_spec.rb:23:in `block (3 levels) in <top (required)>'
You were probably using Webrat earlier, and has_selector? is a Webrat matcher. Capybaras doesn't have a has_selector matcher, it has a matcher called has_css. You may want to replace the "has_selector" with "has_css".
Capybara helpers only works within requests specs. Either create a new request spec, or pass in :type => :request in the describe block part, like so:
describe "test for the testing test", :type => :request do
it "should work with capybara" do
visit root_path
click_link "Home"
page.should WHATEVA
end
end
I realize this question was asked a long time ago, but I thought I would share anyway. GLHF