get value of instance var controller method being tested - ruby-on-rails

I have a method that essentially clones a record. Then redirects to the cloned records edit page. I have a mini test that needs to test that the record gets cloned and redirected to the new records edit path.
#new_record is a new object created in the controller method
describe 'clone_record' do
it 'should clone record' do
#first_record = FactoryGirl.create(:blah)
get :clone_record, :first_record_id => #first_record, :new_record => 'new_record'
assert_redirected_to(edit_record_path(#new_record.id))
end
end
How do I get the value of #new_record in the test?

If you want the most recently created record Record.last should work.

Related

Find a newly created record in a controller test using RSpec 3 and Rails 4

I'm doing a controller spec in Rails 4, and I'm wanting to test the attributes of a record created by a controller action. How do I find the newly created record?
For example, what could I do instead of
it 'Marks a new user as pending' do
post :create, params
# I don't want to use the following line
user = User.last
expect(user).to be_pending
end
The Rails guides only briefly talks about controller tests, where it mentions testing that Article.count changes by 1, but not how to get a new ActiveRecord model.
The question Find the newest record in Rails 3 is about Rails 3.
I'm reluctant to use User.last, because the default sorting may be by something other than creation date.
If a controller has an instance variable named #user, then we can access it in RSpec by assigns(:user).
It is not a good idea to compare records or objects in controller tests. In a controller create test, you should test the correct redirection and the changing of the record.
You can easily compare your objects in a model test, because you can easily track your record.
Still, you can access the created record from a test if your action has a variable that holds the record like
In controller
def create
#user = #assign user
end
In Test
assigns(:user).name.should eq "Name" # If it has a name attribute
assigns(:user).pending.should be_true # I don't know how you implemented pending
You can take a look at this article

Reloading an object not working in rspec

I am trying to test a controller method with the following code:
it "should set an approved_at date and email the campaign's client" do
#campaign = Campaign.create(valid_attributes)
post :approve, id: #campaign.id.to_s
#campaign.reload
#campaign.approved_at.should_not be(nil)
end
However, when I run this test, I get the following error:
Failure/Error: #campaign.reload
ActiveRecord::RecordNotFound:
Couldn't find Campaign without an ID
When I run the analagous lines in the rails console, the reload works and the value is set as I need it to be. Why isn't reload working for me when I run the code in an rspec test?
I solved the problem by switching to FactoryGirl:
#campaign = FactoryGirl.create(:pending_approval_campaign)
#campaign.approved_at.should be(nil)
post :approve, id: #campaign.id.to_s
#campaign.reload
#campaign.approved_at.should_not be(nil)
That works as intended
Two possible places for errors.
object creation. i.e.#campaign = Campaign.create(valid_attributes) Your object may not be created correctly. I suggest you to use create! instead of create in the test so that any error will be thrown.
Controller. When controller expect to find the object with an integer id, you feed it a string. That may also be the problem. I suggest you not to convert the id into string. If for GET, you can do that though not necessary. If for POST, converting to string is wrong.
I would run a test to ensure a Campaign record is actually being created:
#campaign = Campaign.create(valid_attributes)
puts #campaign.id
.reload is the first place in your code that a nil #campaign would flag an error (since you can call .to_s on a nil object)

How to compare assignments in Rspec?

I have the following
it 'should assign a new profile to user' do
get :new
assigns(:user_profile).should ==(Profile.new)
end
But it's not working. I've tried 'eql?' and 'equal?' respectively. How do I compare it in order to know if the contents of #user_profile is Profile.new?
I used to do a workaround doing a .class of the assigned variable, checking if it's Profile but I want to stop with these bad practices.
Thanks.
The problem here is that Object.new invoked twice by design creates two different objects, which are not equal.
1.9.2p318 :001 > Object.new == Object.new
=> false
One thing you can do here is
let(:profile){ Profile.new }
it 'should assign a new profile to user' do
Profile.should_receive(:new).and_return profile
get :new
assigns(:user_profile).should eq profile
end
Now you're not actually creating a new profile when the controller action is invoked, but you are still testing that Profile is receiving new, and you're testing that the return value of that method is being assigned by the controller to #user_profile.

Rspec Rails: testing controller method 'create' with a multi-model form

I am building a Ruby on Rails app with the usual assortment of models, views and controllers.
The 'create' action in one of my controllers is supposed to create an instance of two different models. Here's my code:
def create
#league = League.new(params[:league])
#user = #league.users.build(params[:user])
... .save conditions appended ...
end
So, when you call 'create' through the LeaguesController via a POST request to /leagues, you get a new instance of League and a new instance of User. I also want the new User instance to inherit the ID of the new League instance, so it can be used as the foreign key to link the instances together. This is accomplished with:
def create
#league = League.new(params[:league])
#user = #league.users.build(params[:user])
#league_id = #league.id
#user.update_attribute('league_id', #league_id)
... .save conditions appended ...
end
The User model already belongs_to the League model, which has_many users.
The above code works just fine and dandy, verified via manual testing. However, I can't for the life of me figure out how to automate these tests with Rspec. I'm trying to be a good boy and use test-driven design, but this has me stumped.
The issue is that I can't figure out how to access the attributes of the newly created instances of League and User in my tests. I am attempting to do so using the following code:
describe LeaguesController do
describe 'new league and user' do
it 'should create a new user with a league_id equal to the new leagues id'
#league_attr = { :name => "myleague", :confirmation_code => "mycode", :id => 5}
#user_attr = { :username => "myname", :password => "mypass"}
post :create, :user => #user_attr, :league => #league_attr
assigns(:league_id).should eql(5)
end
end
end
But the test returns nil for the value of :league_id
I'm new to both programming in general and Rspec in particular, so I really appreciate any help someone might offer!
You cannot assign :id with new. Try this:
def create
#league = League.new(params[:league])
#league.id = params[:league][:id] if params[:league][:id]
#user = #league.users.build(params[:user])
#league_id = #league.id
#user.update_attribute('league_id', #league_id)
... .save conditions appended ...
end
That said, I wonder how come it works in the browser.
Also, you better off using FactoryGirl or Fixtures to assign data to models when testing.
Have you tried pry?
Whenever I discover something like this I find it very handy to be able to insert a brakepoint via Pry (or Ruby-Debug) so I can inspect the variables and their behavior.
I suspect putting in a binding.pry between #league_id = #league.id and #user.update_attribute('league_id', #league_id) may very well shed some light on the issue.
Also note that user will automatically inherit the #league_id when you persist it via the #league.save call. (that's the idea behind #league.users.build(..) - it will set the required relationships correctly upon persistance.

Help understanding this RSpec test

I'm trying to firm up my understanding of why this actually works
My application is just the default scaffold for the purposes of this experiment.
it "creates a record and redirects with success notice" do
Project.any_instance.stubs(:valid?).returns(true) #ensure action behaves as if #project was valid
post :create, :format => :js
assigns(:project).errors.should be_empty #ensures that #project has no errors
flash[:notice].should_not be_nil #ensure a flash notice is set
response.should redirect_to(projects_path) #ensure appropriate redirection
end
end
In the controller the save method is called on #project. Here is where I become unsure. The object will save because the valid? method has been stubbed to return true, even if the object is not valid. But if the object is not valid how can the save be successful?
Rails is also calling your valid? stub internally before saving, so it proceeds with the save as normal because it thinks nothing is wrong.
On the other hand if you had, say, a UNIQUE index on a field in a MySQL database, a duplicate row there could still prevent the record from being saved, even though you stubbed valid?. Two possible layers of validation.

Resources