I'm trying to mock Date.today.wday in a rake task in rspec.
Gem versions: RSpec 2.14.8 --- Rails 4.1.1 --- ruby 2.0.0
Here is a simplified fake version of my test to illustrate essentially what I'm trying to do:
describe "scheduler" do
describe ":thursday_invitations" do
let(:run_issue_invites) do
Rake::Task[:thursday_invitations].reenable
Rake.application.invoke_task :thursday_invitations
end
before do
Rake.application.rake_require 'tasks/scheduler'
Rake::Task.define_task(:environment)
Date.today.should_receive(:wday).and_return(4) ###MY NEMESIS CODE LINE
end
context "on thursday" do
it "issues invitations" do
expect(Date.today.wday).to eq(4) ###THE VERIFICATION TEST THAT KEEPS FAILING
run_issue_invites
expect(<other_stuff_to_test>).to <return_properly>
end
end
end
end
So, the real key of this is mocking out the Date.today.wday. Because I want to be able to run my spec on any day of the week, I need to mock/stub out this method to always return "4" (the day-number for Thursday in Rails). So, I initially setup my test to first verify that it is receiving a "4" (the assertion in the test). If today is, say, Friday (which it is) and I run the test, it fails saying that it expected "4" but got "5". That is, it is not returning the value that I want it to when I receive the method. I have tried stubbing with similar ineffective results. Normally, mocking is a breeze, but what seems to be the hangup is .wday which operates on Date.today.
Because this is a rake task (which I'm not as familiar with mocking), I may have to specify something further, but I haven't been able to get to the bottom of it...
Let me know if you need any other clarifying information.
I believe the reason you're not seeing the behavior you expect is that the object you are mocking is the not the same object under test.
In a Rails 4+ environment, this is what I see on the rails console:
[1]> Date.today.object_id
70104549170200
[2]> Date.today.object_id
70104552970360
The fact that the object_id is different in subsequent calls to Date.today means that each call returns a new object. So Date.today.should_receive(:wday).and_return(4) is setting an expectation on an object that will never be used again.
You'll need to rewrite your spec to ensure the same object is returned by Date.today each time. Here's one solution, omitting other parts of your example for clarity:
let!(:today) { Date.today }
before do
Date.stub(:today).and_return(today)
today.should_receive(:wday).and_return(4)
end
it "issues invitations" do
expect(Date.today.wday).to eq(4)
end
Related
I am trying to wrap Timecop around a shared_example spec i wrote
describe "timecop wrapping shared example" do
Timecop.freeze(1.day.ago) do
it_behaves_like "a shared example i would like to test using timecop"
end
end
shared_examples "a shared example i would like to test using timecop"
before :all do
puts "the current time is #{Time.now}"
end
... expect ...
end
but running this spec still uses the real time and not the frozen one
can Timecop work like this?
how else can i wrap large pieces of my test file but change the time it is running
Timecop needs to execute within an it or before block.
The following change will fix your problem.
describe "timecop wrapping shared example" do
before { Timecop.freeze(1.day.ago) }
it_behaves_like "a shared example i would like to test using timecop"
end
Rspec will reset the environment(including Timecop) after running each example.
A couple of tips I've found with time travel in tests that might be useful:
Timecop.travel is more reflective of how your code will work in real life as time never stays still. You can use it the same way as freeze, just swap out the freeze method for travel.
If you have Rails 4.1 or newer there are great time travel tools built in and you can drop your timecop gem. Here is a blog post and the docs if you want to learn more.
In Michael Hartl's Rails Tutorial, many examples use an expect() method. Here's one such example in a cucumber step definition:
Then /^she should see her profile page$/ do
expect(page).to have_title(#user.name)
end
This same example can be written as such to the same effect:
Then /^she should see her profile page$/ do
page.should have_title(#user.name)
end
Why use expect()? What value does it add?
There's a documentation on the rspec-expectations gem about this.
Why switch over from should to expect Basically:
should and should_not work by being added to every object. However, RSpec does not own every object and cannot ensure they work consistently on every object. In particular, they can lead to surprising failures when used with BasicObject-subclassed proxy objects.
expect avoids these problems altogether by not needing to be available on all objects.
A more detailed reasons for this is placed in: RSpec's New Expectation Syntax
expect is a bit more universal. You're passing an object or a block to rspec's expect method, rather than attempting to call a should method on objects that are outside of your control. As a result, expect is coming more and more into favor among developers.
New to Ruby, Rails and TDD. I'm using RSpec with Capybara and Capybara webkit.
Trying to test if a div element exists on a page.
Test Code:
require 'spec_helper'
describe "Login module" do
before do
visit root_path
end
it "should have a module container with id mLogin" do
page.should have_css('div#mLogin')
end
it "should have a module container with id mLogin", :js => true do
page.evaluate_script('$("div#mLogin").attr("id")').should eq "mLogin"
end
end
The first test passes but the second test fails with:
Login module should have a module container with id mLogin
Failure/Error: page.evaluate_script('$("div#mLogin").attr("id")').should eq "mLogin"
expected: "mLogin"
got: nil
Ran the JS in browser dev tools and get "mLogin" rather than nil.
Any ideas? Thanks.
find('div#mLogin')[:id].should eq 'mLogin'
See this from doc:
#evaluate_script
Evaluate the given JavaScript and return the result. Be careful when using this with scripts that return complex objects, such as jQuery statements. execute_script might be a better alternative.
evaluate_script always return nil, as far as I remember.
Anyway, your second test seems like is testing if capybara works, because your first test is enough.
One likely problem is that the have_css matcher supports Capybara's synchronization feature. If the selector isn't found right away, it will wait and retry until it is found or a timeout elapses.
There's more documentation about this at http://rubydoc.info/github/jnicklas/capybara#Asynchronous_JavaScript__Ajax_and_friends_
On the other hand, evaluate_script runs immediately. Since this is the first thing you do after visiting the page, there's a race condition: it's possible that it executes this script before the page has finished loading.
You can fix this by trying to find an element on the page that won't appear until the page is loaded before you call evaluate_script.
Alternately, you can wrap your call in a call to synchronize to explicitly retry, but this is not generally recommended. For situations like this, you're much better off using Capybara's built-in matchers. The evaluate_script method should only be used as a last resort when there is no built-in way to accomplish what you need to do, and you need to take a lot of care to avoid race conditions.
Similar to the problem described here:
http://rpheath.com/posts/411-how-to-use-factory-girl-with-rspec
in Short (shorten'd code):
spec_helper:
config.use_transactional_fixtures = true
config.use_instantiated_fixtures = false
factories.rb:
Factory.define :state do
f.name "NY"
end
in my spec
before(:each) do
#static_model = Factory(:state) # with validate uniqueness of state name
end
error:
duplicate entry name "NY" etc.
Question:
Shouldn't rspec clear database before each spec example and hence not throwing duplicate entry errors?
Things i think off:
do you use rake spec to run your testsuite: that builds up the database from scratch (to make sure nothing is sticking)
do you use, anywhere, a before (:all) ? Because whatever you create inside a before :all should be deleted again in a after :all or it keeps on existing.
Question: Shouldn't rspec clear database before each spec example and hence not throwing duplicate entry errors?
RSpec with DatabaseCleaner or RSpec Rails with use_transactional_fixtures will clear the DB as long as your created the data in the example itself. before :all do ... end is considered outside of the example, because the data remains untouched across multiple examples. Whatever you create in before :all you have to delete in after :all.
In order to delete whatever you create automatically use before :each do ... end. Be aware the same data will be created and removed 10 times if you have 10 examples. The difference between before :all and before :each is better explained here: rails rspec before all vs before each
Some more possible causes:
There's still a states.yml fixture sitting around
Someone played around on script/console test and forgot to clean up afterwards.
You might also find it's because you haven't wrapped the statement in:
describe "what it should do" do
#static_model = Factory(:state) # with validate uniqueness of state name
end
I discovered that was the change that solved this problem:
Why isn't factory_girl operating transactionally for me? - rows remain in database after tests
I have had similar questions about what sort of starting state one can expect when using FG and RSpec.
While I too wait for clarity, Database Cleaner could be a good fix: http://rubydoc.info/gems/database_cleaner/0.6.7/frames
hth -
Perry
When you use Factory(:state) wich is a shortcut to Factory.create(:state), factory_girl returns you a saved object.
Use Factory.build(:state) instead.
Dude maybe your yaml fixtures from regular unit tests get mixed into your rspec?
I've been trying to solve a problem for a few weeks now. I am running rspec tests for my Rails app, and they are working fine except for one error that I can't seem get my head around.
I am using MySQL with the InnoDB engine.
I have set config.use_transactional_fixtures = true in spec_helper.rb
I load my test fixtures manually with the command rake spec:db:fixtures:load.
The rspec test is being written for a BackgrounDRb worker, and it is testing that a record can have its state updated (through the state_machine gem).
Here is my problem:
I have a model called Listings. The rspec test calls the update_sold_items method within a file called listing_worker.rb.
This method calls listing.sell for a particular record, which sets the listing record's 'state' column to 'sold'.
So far, this is all working fine, but when the update_sold_items method finishes, my rspec test fails here:
listing = Listing.find_by_listing_id(listing_id)
listing.state.should == "sold"
expected: "sold",
got: "current" (using ==)
I've been trying to track down why the state change is not persisting, but am pretty much lost. Here is the result of some debugging code that I placed in the update_sold_items method during the test:
pp listing.state # => "current"
listing.sell!
listing.save!
pp listing.state # => "sold"
listing.reload
pp listing.state # => "current"
I cannot understand why it saves perfectly fine, but then reverts back to the original record whenever I call reload, or Listing.find etc.
Thanks for reading this, and please ask any questions if I haven't given enough information.
Thanks for your help,
Nathan B
P.S. I don't have a problem creating new records for other classes, and testing those records. It only seems to be a problem when I am updating records that already exist in the database.
I suspect, like nathan, transaction issues. Try putting a Listing.connection.execute("COMMIT") right before your first save call to break the transaction and see what changes. That will break you out of the transaction so any additional rollback calls will be non-effectual.
Additionally, by running a "COMMIT" command, you could pause the test with a debugger and inspect the database from another client to see what's going on.
The other hypothesis, if the transaction experimentation doesn't yield any results, is that perhaps your model really isn't saving to the database. Check your query logs. (Specifically find the update query).
These kind of issues really stink! Good luck!
If you want to investigate what you have in DB while running tests you might find this helpful...
I have a rspec test where I save #user.save and it works like a charm, but then I wanted to see if it's really saved in the DB.
I opened rails console for test environment
rails c test
ran
User.all
and as expected got nothing
I ran my spec that contains:
user_attr_hash = FactoryGirl.attributes_for(:user)
#user = User.new user_attr_hash
#user.save
binding.pry
I thought that stopping the test after save would mean that it's persisted, but that's not the case. It seems that COMMIT on the connection is fired later (I have no idea when:\ )
So, as #Tim Harper suggests, you have to fire that commit yourself in the pry console:
pry(#<RSpec::Core::ExampleGroup::Nested_1>)> User.connection.execute("COMMIT")
Now, if you run User.all in your rails console you should see it ;)