I guess I am missing something very very obvious, but in my RSpec tests I want to do something like this:
it "should assign all channels to #channels" do
get :index
assigns(:channels).should eq(channels(:all))
end
As you can see I want all channels in an array for my tests so I don't have to fix all my tests when I add a new fixture in the future.
channels(:all) is not working and channels.kind_of? Array is true and empty by default.
Any suggestions?
What you might need is:
assigns(:channels).should eq(Channel.all)
Related
Using Mocha on Rails 4.2.
I'm testing a method that it should make a call to another method with the correct parameters. These parameters are ActiveRecord objects that it calls up from the database. Here is the key line in my test:
UserMailer.expects(:prompt_champion).with(users(:emma), [[language, 31.days.ago]]).once
Both users(:emma) and language are ActiveRecord objects.
Even though the correct call is made, the test fails because the parameters don't match the expectations. I think this might be because it's a different Ruby object each time a record is pulled up from the database.
I think one way around it is to see what method is being used in my code to pull up the records and stub that method to return mocks, but I don't want to do this because a whole bunch of Records are retrieved then filtered down to get to the right one, mocking all those records would make the test way too complex.
Is there a better way of doing this?
You could use block form of allow/expect.
expect(UserMailer).to receive(:prompt_champion) do |user, date|
expect(user.name).to eq "Emma"
expect(date).to eq 31.days.ago # or whatever
end
Sergio gave the best answer and I accepted it. I discovered the answer independently and found out along the way that I needed to return a mock from the ActionMailer method to make everything work properly.
I think it best to post here my complete test here for the sake of any other hapless adventurer to come this way. I'm using Minitest-Spec.
it 'prompts champions when there have been no edits for over a month' do
language.updated_at = 31.days.ago
language.champion = users(:emma)
language.save
mail = mock()
mail.stubs(:deliver_now).returns(true)
UserMailer.expects(:prompt_champion).with do |user, languages|
_(user.id).must_equal language.champion_id
_(languages.first.first.id).must_equal language.id
end.once.returns(mail)
Language.prompt_champions
end
You could use an RSpec custom matcher and compare expected values in that function.
I am newbie to testing. Can someone help me how to test the current_user in rspec.
Example code:
Easy one:
def index
#todos = current_user.todos
end
a bit more hard one
def index
#events = current_user.participating_events.includes(
[:events_users, :participants, :user])
end
How can I write rspec tests for similar kind of problems.
Because it's an integration test, you should strive for actual login so that the spec manages the session created by the controller. You can follow the ideas on this answer, but basically you need to authenticate with a given user. But that you are already doing, so maybe the problem you are having is not clear by the question.
One thing I noticed weird on your tests is that event is checked for some tests, but I can't see where it is defined. It's like you expected it to be set by rspec in some way. If that's the case, then that might be the problem you are having. For this kind of spec, you should load objects from the db to test if they were created, so after filling the form and saving the event, before testing the result, load it from the DB with
event = Event.last
and then probe it for the values stored.
Let me know if this makes sense and if this solves your problem. Otherwise, maybe try to clarify what are you trying to accomplish or post a backtrace of any error you are having.
Is it possible to do something like ServiceObject.should_receive(:foo).with(:bar).and_call_original.exacly(1).times?
My specs look something like this:
it 'should call instance of service object\'s :baz! method' do
ServiceObject.any_instance.should_receive(:baz!).exactly(1).times
end
it 'should call service object\'s :foo method' do
ServiceObject.should_receive(:foo).with(:bar).and_call_original.exacly(1).times
end
If I remove and_call_original the first spec fails. If I comment out the .exacly(1).times in the second spec both specs pass.
Two questions:
Why do these two specs interfere with one another?
Is there a way to call something that means .should_receive(:foo).with(:bar).and_call_original.exacly(1).times?
Thanks in advance!
and_call_original doesn't return the current example so it cannot work.
Instead you can do:
.should_receive(:foo).with(:bar).exacly(1).times.and_call_original
I have a test with failing despite knowing the functionality works in the app. My instinct says that I should try saving the thing that I create but I'm not sure how to do this in the assert_difference block beacause it doesn't look like the new thing is assigned to a variable on which I can .save. Thanks for any advice you can provide.
Test:
test "should create thing" do
assert_difference('thing.count') do
post :create, thing: { thing_type_id: #thing.thing_type_id, name: #thing.name}
end
Output:
1) Failure:
test_should_create_thing(thingsControllerTest) [C:/../thing_controller_test.rb:20]:
"thing.count" didn't change by 1.
<3> expected but was
<2>.
Sounds like you may have some left over state in your database. I see that expected but was <2>, meaning you already have two Things in your DB.
You can try clearing the DB state between tests. Depending on your database check out the database_cleaner gem.
Also, it seems you may have already created the object, by the existence of #thing. If that is the case, this is working as expected.
You can take the controller out of the equation to verify this by just testing a normal Thing::create:
test "creates a new Thing" do
assert_difference('Thing.count') do
Thing.create thing_type_id: #thing.thing_type_id, name: #thing.name
end
end
What's the best practices way to test that a model is valid in rails?
For example, if I have a User model that validates the uniqueness of an email_address property, how do I check that posting the form returned an error (or better yet, specifically returned an error for that field).
I feel like this should be something obvious, but as I'm quickly finding out, I still don't quite have the vocabulary required to effectively google ruby questions.
The easiest way would probably be:
class UserEmailAddressDuplicateTest < ActiveSupport::TestCase
def setup
#email = "test#example.org"
#user1, #user2 = User.create(:email => #email), User.new(:email => #email)
end
def test_user_should_not_be_valid_given_duplicate_email_addresses
assert !#user2.valid?
end
def test_user_should_produce_error_for_duplicate_email_address
# Test for the default error message.
assert_equal "has already been taken", #user2.errors.on(:email)
end
end
Of course it's possible that you don't want to create a separate test case for this behaviour, in which case you could duplicate the logic in the setup method and include it in both tests (or put it in a private method).
Alternatively you could store the first (reference) user in a fixture such as fixtures/users.yml, and simply instantiate a new user with a duplicate address in each test.
Refactor as you see fit!
http://thoughtbot.com/projects/shoulda/
Shoulda includes macros for testing things like validators along with many other things. Worth checking out for TDD.
errors.on is what you want
http://api.rubyonrails.org/classes/ActiveRecord/Errors.html#M002496
#obj.errors.on(:email) will return nil if field is valid, and the error messages either in a String or Array of Strings if there are one or more errors.
Testing the model via unit tests is, of course, step one. However, that doesn't necessarily guarantee that the user will get the feedback they need.
Section 4 of the Rails Guide on Testing has a lot of good information on functional testing (i.e. testing controllers and views). You have a couple of basic options here: check that the flash has a message in it about the error, or use assert_select to find the actual HTML elements that should have been generated in case of an error. The latter is really the only way to test that the user will actually get the message.