assigns() method vs Binding - Rails - ruby-on-rails

I'm new to Ruby on Rails world.
I noticed there is at least one way to access controller instance variables from a test case.
Indeed, suppose this test method:
test "should get index" do
get :index
assert_response :success
assert_not_nil assigns(:products)
end
products is an instance variable contained within concerned controller. And for sure, test case has reference to this controller. So assigns() method uses it to inspect a hash of controller's instance variables and thus allows to access any precised object from any other files that previously called an action to this controller.
So I wonder two questions:
Why do not create a 'Binding' to controller instead of using assigns() method?
I imagine a version where it is possible to do:
test "should get index" do
get :index
assert_response :success
assert_not_nil #products
end
Wouldn't it be shorter and cleaner?
Binding is the mechanism that allows ERB file to access controller instance variables, as shows this links:
http://rrn.dk/rubys-erb-templating-system
What isn't this mechanism applicable to Test case ? Is assigns() method essential ?

If you brought over the binding, though, this might pass and should not
test "should get index" do
#fake_products = [1,2,3]
get :index
assert_response :success
assert_not_nil #fake_products
end
You wouldn't necessarily want all instance variables in your test to combine with instance variables in your controller. Assigns lets you 'scope' your assertions to just the controller instance variables.

Related

`Assigns` isn't working in my integration test

I'm trying to write a test following the suggestion on https://stackoverflow.com/a/17002140/4499505.
My simplified test:
test "test" do
log_in_as(#user)
get users_path
assert_template 'users/index'
assigns[:users].each do
assert_select 'a[href=?]', users_path(user)
end
end
The error result:
NoMethodError: undefined method `each' for nil:NilClass
The controller method:
def index
#users_grid = initialize_grid(User.where(verified: true),
per_page: 15,
order: 'users.username',
order_direction: 'desc')
end
Apparantly assigns[:users] is empty even though there are users in the fixtures file. What am I doing wrong? I understand the assigns[:users] should assign the exact same users as shown on users/index, which is exactly what I want.
Well, your correct code is :
test "test" do
log_in_as(#user)
get users_path
assert_template 'users/index'
# in your controller you have the instance var as
# #users_gird, not #users.
assigns[:users_grid].each do
assert_select 'a[href=?]', users_path(#user)
end
end
assigns is a hash, accessible within Rails tests, containing all the instance variables that would be available to a view at this point. It’s also an accessor that allows you to look up an attribute with a symbol (since, historically, the assigns hash’s keys are all strings). In other words, assigns(:contact) is the same as assigns["contact"].
Notice in the answer you've linked to that the symbol in assigns[] matches that of the instance variable from the controller action.
In your case you're assigning the instance variable #users_grid but attempting to iterate through assigns[:users]. You probably just want to change the latter to assigns[:users_grid]

When creating using a custom rspec matcher in and example group, the message is empty

I'm using a custom rspec matcher within a controller spec the message is always empty.
The spec looks like:
describe QuestionnaireController do
matcher :redirect_to_sign_in_if_not_authenticated do |method|
match do |controller|
self.send(method)
response.should redirect_to new_user_session_path
end
end
describe "GET index" do
it { should redirect_to_sign_in_if_not_authenticated(get :index) }
end
end
When running this test, and it fails, all that comes up is:
Failures:
1) QuestionnaireController GET show
As you can see the default should message is missing here. How do I get it to show up?
You can use a failure_message_for_should block, as described here: https://www.relishapp.com/rspec/rspec-expectations/v/2-4/docs/custom-matchers/define-matcher#overriding-the-failure-message-for-should
However, you're probably going to run into a few problems here:
get :index will actually call the get method, and then pass the return value to the matcher, which the code does not seem to be expecting.
Errors & backtraces will probably be messed up if you use another matcher (should redirect_to) inside your custom matcher.
You might want to consider a shared example instead: https://www.relishapp.com/rspec/rspec-core/docs/example-groups/shared-examples

Basic New Action Testing ActionController::TestCase

I am somewhat new to testing in rails, and I'm wondering if this is a sufficient test for my new controller.
test "should get new" do
get :new
assert_response :success
end
Controller:
def new
#question = Question.new
end
Because the new action stores the controller in memory and does not write it to the DB, nor does it validate it. This seems sufficient to me. Any thoughts?
Controller testing should generally assert a few things
Controller rendered the correct template
You redirected to the right place
The instance variable has the correct data
Sometimes I also send some extra post variables in to make sure someone isn't goin to be able to curl themselves into an admin.

Mocha expectation on association build call failing

I have this example:
# GET New
context "on get to new" do
it "should assign cardset" do
#profile.cardsets.expects(:build).once.returns(Factory.stub(:cardset))
get :new
assigns[:cardset].should_not be_nil
end
end
To test this method:
# GET /cardsets/new
def new
#cardset = current_user.cardsets.build
end
I am trying to enforce that the association is built from current_user to make sure the user is only creating things that belong to themselves. I am using an expectation very similarly to ensure they are calling find from the current_user object and it works find, but when running the above example I get:
6)
Mocha::ExpectationError in 'CardsetsController for a logged in user on get to new should assign cardset'
not all expectations were satisfied
unsatisfied expectations:
- expected exactly once, not yet invoked: [#<Cardset:0x102eaa8c8>, #<Cardset:0x102e12438>].build(any_parameters)
satisfied expectations:
- allowed any number of times, not yet invoked: ApplicationController.require_user(any_parameters)
- allowed any number of times, already invoked twice: #<CardsetsController:0x1030849c8>.current_user(any_parameters)
/Applications/MAMP/htdocs/my_app/spec/controllers/cardsets_controller_spec.rb:32:
You add the expectation to #profile after you've stubbed the function that returns it from current_user. Probably what you need to do is this:
# GET New
context "on get to new" do
it "should assign cardset" do
#profile.cardsets.expects(:build).once.returns(Factory.stub(:cardset))
controller.stubs(:current_user).returns(#profile)
get :new
assigns[:cardset].should_not be_nil
end
end

Rails: RSpec controller test passes without action being implemented, why?

I have the following RSpec example which is passing:
describe UsersController do
it "should render new template on new action" do
get :new
response.should render_template("users/new")
end
end
The problem is I have not implemented the 'new' action on the UsersController.
Can anyone tell me why this test is passing?
I am new to RSpec, so any tips would be greatly appreciated!
When requesting an action for which a view exists, but the action is not defined, Rails will simply render the view. Therefore your spec (correctly) passes.
In addition to this spec, you may want to test for the assignment of particular instance variables. Example:
it "should assign the found articles for the view" do
assigns[:article].should == [#article]
end

Resources