I have a standard Rails 3.2 app with some weird behavior going on.
I can run rspec spec/ without spork running and all tests pass no problem.
Then I fire up spork and run the specs again. This time, every test that touches one of my mailers will fail with the same error:
Failures:
1) InvitationsController GET accept with non-matching token should redirect to the root path
Failure/Error: let!(:invitation) { Factory :invitation }
NoMethodError:
undefined method `invite' for InvitationMailer:Class
# ./app/models/invitation.rb:29:in `send_email'
# ./spec/controllers/invitations_controller_spec.rb:5:in `block (3 levels) in <top (required)>'
Then, just to make it all a little weirder, I can run individual directories or specs, with or without spork running, and everything passes no problem. e.g rspec spec/mailers or rspec spec/models.
Here is the method which I am being told is undefined:
class InvitationMailer < ActionMailer::Base
default from: APP_CONFIG[:default_from]
def invite(invitation)
#invitation = invitation
mail(to: #invitation.recipient_email, subject: "the subject")
end
end
Any ideas what could be happening?
After spending some time tweaking Spork, I think it is possible to fix this.
For some reason, Spork is not loading the InvitationMailer file. So, the one thing you can do is require it within the Spork.each_run do block.
Also, here is the process I have used to diagnose Spork issues:
Move everything in the spec helper except for require 'spork' to inside the Spork.prefork do block. Make sure there are no errors. Use time to see how fast.
Move some code into the Spork.each_run do block.
Check to see if the the error happens. Use time to see how fast the tests run.
See if the error occurs. If so, then move some code back to pre_fork.
Keep moving stuff around until you figure out what needs to be in the prefork block and how much faster it runs.
This process was explained in this RailsCast.
Related
I've got a class inside app/models/parser called data.rb with contents :
class Parser::Data
def method1
end
end
Nothing fancy at this point. I'm trying to write a test for it before implementing too much, just did default RSpec install for Rails.
My RSpec file is in spec/models/parser/data_spec.rb and is very basic so far:
require 'spec_helper.rb'
describe Parser::Data do
let(:parser) { Parser::Data.new }
end
When I run the test I get this error:
spec/models/parser/data_spec.rb:3:in `<top (required)>': uninitialized constant Parser (NameError)
I tried placing module Parser around the Data class in the same directory app/models/parser, also I've tried moving it to lib/parser doing the same module wrapping class, and added lib/parser to autoload in the application.rb but nothing has worked so far.
What am I doing wrong?
require 'rails_helper' instead of spec_helper. Requiring only spec_helper reproduces the issue for me, and requiring rails_helper fixes it. More on spec_helper vs. rails_helper (including performance implications) here: How is spec/rails_helper.rb different from spec/spec_helper.rb? Do I need it?
I reproduced the problem by running RSpec with bundle exec rspec. If I run RSpec with bin/rspec (that's a binstub generated by the spring-commands-rspec gem) it doesn't care which helper file I require. I guess spring loads more eagerly.
When I run view specs manually (zeus rspec or rake spec) I am getting errors raised if Devise or CanCanCan helpers are present in the view
Failure/Error: <% if user_signed_in? %>
ActionView::Template::Error: undefined method `authenticate' for
nil:NilClass
Failure/Error: <% if can? :update, #object %>
ActionView::Template::Error: undefined method `authenticate' for
nil:NilClass
When the same specs are run via Guard, no errors are raised and the specs pass.
Adding the following to the view spec causes both Guard and manually launched specs to pass.
...
#ability = Object.new
#ability.extend(CanCan::Ability)
controller.stub(:current_ability) { #ability }
controller.stub(:user_signed_in?) {false}
...
(I also tried including config.include Devise::TestHelpers, type: :view in a support file but this did not appear to do anything)
Why would Guard-launched and manually-launched specs behave
differently?
Are these controller stubs the 'correct' way to deal
with this issue?
Why would Guard-launched and manually-launched specs behave differently?
The best way is to run Guard in debug mode: bundle exec guard -d. It will show you the actual rspec command being run. Then, you can compare that to how you're invoking rspec.
The second thing could be: you may be running different versions of gems. Try bundle exec rspec vs bundle exec guard. There shouldn't be differences. You can then experiment with zeus, etc.
Are these controller stubs the 'correct' way to deal with this issue?
I'd say it's best to use Cucumber/Capybara for testing views. It isn't as fast and the effort to mock the views is probably just not worth the time.
But otherwise, it doesn't matter how you stub/mock as long as you're testing what matters. For views, I think that means testing to make sure the right instance variables are used to generate the views. Testing the actually html generated probably isn't too convenient.
Views change often, too - so too much testing there can be a waste of time with little gain. Even if you make errors in views, they're usually easy to spot, quick to fix and there aren't too many edge cases. (Those are usually handled by controllers). So again, using Cucumber+Capybara gives you more tools, more flexibility and enough coverage without sacrificing your freedom to change things without being forced to update tests as well.
The reason for devise helpers is to get sign_in and sign_out working. That's pretty much it. So if those don't work, you likely don't have the helper included.
I also tried including config.include Devise::TestHelpers, type: :view in a support file but this did not appear to do anything
Are you sure that support file was actually included? Usually nowadays you have to do that explicitly in the spec_helper.rb file.
Not quite sure what's going on here. I'm moving over some code from another project of mine and suddenly the same specs from before are generating errors in the new project. All the errors appear to revolve around calling the stub method. Here's an example test:
it "retrieves active workers from Redis" do
#monitor.should_receive(:monitor_running?).and_return(false)
REDIS.should_receive( :smembers ).with( 'leaderboard-workers' ).and_return( [] )
#monitor.perform
end
This works. However if I switch the first test line to this:
#monitor.stub(:monitor_running?).and_return(false)
I end up with the following error:
1) LeaderboardMonitor#perform retrieves active workers from Redis
Failure/Error: #monitor.stub(:monitor_running?).and_return(false)
Mocha::ExpectationError:
unexpected invocation: #<Mock:0x7fcc18c8bab8>.and_return(false)
satisfied expectations:
- allowed any number of times, not yet invoked: #<Mock:0x7fcc18c8bab8>.monitor_running?(any_parameters)
# ./spec/workers/leaderboards/leaderboard_monitor_spec.rb:58:in `block (3 levels) in <top (required)>'
I'm not quite sure what's going on here. Is this an issue with Mocha overriding the stub method? How do I work around this?!?!?
I don't know what version of mocha you are using. Have you tried something like
#monitor.expects(:monitor_running?).returns(false).at_least_once
Hello i am receiving this error:
spec/models/stores/persistent_spec.rb:6:in block (2 levels) in <top
(required)>': undefined methodexpect' for #
(NoMethodError)
Here is my setup. i have a class called Store located inside app/models
i have a class called Stores::Temporary < Store placed inside app/models/stores
I am trying to write tests for Temporary and they are failing with the error above
i have created temporary_spec.rb inside spec/models/stores and the code for it is the following:
require "spec_helper"
describe Stores::Temporary do
end
i am trying to write an expect to raise_error statement.
I have also tried 5.should == 5 which results with no available test being detected inside this file. I am using guard to autorun the tests, so changes in the files are being detected (works correctly) and tests are rerun but appear as blank.
So after struggling with this for 2 hours i restarted the PC and it was working without changing anything... One of those stupid errors you just need to sorta sleep-over and retry.
I'm having a hard time getting any consistant behavior from Mocha and the regexp_matches method. If autotest runs my entire test suite everything works fine. If I purposely cause the test containing the regexp_matches call to fail and then fix it I get a method_missing error on regexp_matches. If I then run the entire test suite again, everything is fine. The bigger problem is coming from Hudson (continuous integration). It runs the entire test suite but always says regexp_matches is missing and I don't know how to fix it.
My test:
test "if token is set during Account creation the long url should be created correctly" do
Account.any_instance.expects(:http_get).with("api.server.com", regexp_matches(%r(^http://.*/accounts/\d+/jobs$)))
account = Account.create name: "New Account", token: "NewToken"
end
The error:
test_if_token_is_set_during_Account_creation_the_long_url_should_be_created_correctly(AccountTest):
NoMethodError: undefined method `regexp_matches' for #<AccountTest:0x0000010162d0c0>
test/unit/account_test.rb:158:in `block in <class:AccountTest>'
I don't even know what other code to add here as I can't imagine what the cause is. For giggles I pasted require 'mocha' at the top of the test file but that didn't change anything.
I ran into this problem on a rails project when removing
require 'spec_helper'
I did this so that running the spec would not load the whole rails environment. This means that external dependencies have to be required or mocked. Mocha obviously needs to be required.
But even after specifying
require 'mocha'
I ran into the same method missing issue.
Ultimately, I solved it by including the parameter matchers module directly:
require_relative "../../../lib/some_class"
require "mocha"
include Mocha::ParameterMatchers
describe SomeClass do
it "should do things" do
...