RSpec integration testing -- instance variable in application controller is nil - ruby-on-rails

Recently started a new job, no ruby/rails experience before this gig so bare with me.
Currently I have a method defined in my application controller which has a few instance variables defined, and is being called :before_action do_something_on_start
There is an instance variable that grabs an entry from our database and I set some instance variables that will be available in the view
def do_something_on_start
#test = User.find_by(id: 1)
#enabled = #test.value == "true"
#start_date = #test.start_date
end
When running our suite of test specs, most of the feature specs come back with undefined method `value' for nil:NilClass
Not entirely sure why this is happening. Are the instance variables not available to the test spec when they run? Or do I have to have those same instance variables defined in all of our feature specs to work?

The error message is telling you that #test is nil, which means your DB doesn't contain a User with id 1. Generally test data is reset between each test, so that tests are isolated and order independent. Because of that you need to look at how you're setting up your test data either via fixtures, as mentioned by #arieljuod, or via factories using something like FactoryBot.

Related

how do I test a private method on controller, using minitest?

Very new to testing
I have a model-less rails app with a controller called "PokerController"
in poker_controller.rb, I have a private method that looks like this:
private
def test(x)
1 + x
end
Then I have a file called 'poker_controller_test.rb' in test/controllers
I'm trying to do something like this:
require 'test_helper'
class PokerControllerTest < ActionController::TestCase
test "check if test == 2" do
test = test(1)
assert test == 2
end
end
As you can see, I'm trying to save the result of the function 'test' being called, to a variable called 'test' then I'm checking to see if that == 2.
Basically, I'm trying to pass in a number (in this case '1') to the test method, and I want the test to add 1 to 1, and expect to get 2.
I'm sure I'm just not setting up the test right, but how do I call a custom method like this and then evaluate what's returned?
Here's my result from the error in the test:
Error:
PokerControllerTest#test_check_if_test_==_2:
ArgumentError: unknown command "\x01"
test/controllers/poker_controller_test.rb:6:in `test'
test/controllers/poker_controller_test.rb:6:in `block in <class:PokerControllerTest>'
You don't.
Testing private methods in general is frowned upon*.
In Rails you mainly test controllers through integration tests. These are tests that send real HTTP requests to your application and then you write assertions about the response or the side effects of sending the request.
"[...] You can test what cookies are set, what HTTP code is returned, how the view looks, or what mutations happened to the DB, but testing the innards of the controller is just not a good idea."
- David Heinemeier Hansson
An example of an integration test is:
require "test_helper"
class PokerControllerTest < ActionDispatch::IntegrationTest
test "can see the welcome page" do
get "/path/to/somewhere"
assert_select "h1", "Welcome to my awesome poker app"
end
end
If you have a method that you want to test in isolation it does not belong in your controller in the first place and arguably it should not be a private method either.
You should test the public API of your objects. The public API of a controller is the methods that respond to HTTP requests via the router.
The use of ActionController::TestCase is discouraged outside of legacy applications.
New Rails applications no longer generate functional style controller
tests and they should only be used for backward compatibility.
Integration style controller tests perform actual requests, whereas
functional style controller tests merely simulate a request. Besides,
integration tests are as fast as functional tests and provide lot of
helpers such as as, parsed_body for effective testing of controller
actions including even API endpoints.
Besides that the issues with your test is that you're calling the test method on the instance of ActionController::TestCase and not your controller. You're then shadowing the method by defining an instance variable with the same name which is rarely a good thing.
Even if you did call the method on the controller Ruby would still raise an error since you're calling a private method from outside the object - thats the whole point of private methods.
While you could violate encapsulation by calling #controller.send(:test) this is just a bad idea on so many levels.

How does assigns know where to look for the instance variable in integration tests?

I've been following a rails tutorial and got to know the assigns method of Rspec.
This is how it's being used in an integration test:
class SomeTest < ActionDispatch::IntegrationTest
test "simplified test" do
get '/some/path'
#some assertions
get '/other/path'
assert_equal 'changed', assigns(:some_variable)
end
end
Assigns seem to access the controller/view of the last call.
Is that so? how does assigns get to the instance variable some_variable?
It seems to imply there is some state being preserved in the integration test that is accessed from assigns.
It turned out that Rails treat Integration tests pretty much like functional ones, so the instance variables described in the documentation for the latter works in the former. In integration tests these variables tend to be overwritten, so you'll access the state prior to your call.
That means that in an integration test you may access:
#controller: the last controller being invoked
#request: the last request sent
#response: the last response object returned
assings just wraps the access to #controller.view_assigns where all the instance variables that will be available for the view are held.

How to get the value of a Controller variable in rails console

I set a variable inside a Controller and I'm trying to just do something as simple as read that variable in the rails console.
I thought about just doing #test in the console which is the name of the variable. but it shows as >null. When I do puts under where I set the variable it traces out the correct value in my terminal window.
Any ideas what I need to do to get to this variable via the console.
I tried putting the name of the controller first and then .variable but that threw an error
I can see what's inside my models by just using the model name and some attributes like .first and .last
You'd have to instantiate the controller and provide a public accessor to get the value in rails console.
If you're trying to debug something, I recommend you check out Pry. It's a Ruby debugging REPL. Do a require 'pry' in your controller, and put binding.pry somewhere in an action, when you execute that controller method--either interactively in a browser, or via a functional test (I recommend the latter)--it will open the Pry REPL and #test will be in scope there.
Check out this Railscast for some help using it.
Alternately, just rely on good unit or functional testing. Write a test around the method and add an assertion on assigns(:#test) to compare the value to your expectation. Check out the RSpec controller spec documentation.

How do you add a variable to the global scope? (ruby on rails)

So, I'm trying to do some unit tests, and my current_account_permissions variable is undefined when running the tests. (works fine when the server is running).
It's similar to current_user in that it's available everywhere, except tests apparently.
Is there a way I can add the variable to the global scope?
Maybe something like ENV["current_account_permissions"] = whatever but not having to use the ENV[] notation to retrieve the variable?
I am assuming here, but without any code it is hard to tell, that somehow the current_account_permissions is mixed in into the ApplicationController.
I would also assume that the current_account_permissions is a method, which should do something like
def current_account_permissions
#current_account_permissions ||= current_user.get_current_account_permissions
end
So if that is the case, all your controller tests would run fine as dandy. In your view tests however, you will have to stub the current_account_permissions because when testing there is no controller context.
Hope this helps.

validation of controller-assigned variables in rails integration tests

I'm beginning with Rails and currently I got stuck on integration testing of controllers.
I'm trying to validate that if certain values are provided by a user in a form, Active Record generates errors and these errors are passed to a view.
My problem is that I have no idea how to access controller assigned variables (for example - #user) inside integration tests. As I read in http://guides.rubyonrails.org/testing.html#what-to-include-in-your-functional-tests I can access variables such as #controller, #request, #response but I was also expecting that I can easily access variables assigned by controller.
Unfortunately things such as:
* #user
* #controller.user
don't really work :-/
Rails Version < 5.0
You can access these variables using assigns method with symbol of variable name as a perameter. In example:
assigns(:user)
Gives you value of #user from your controller.
Rails Version > 5.0
In rails 5.0 assigns and assert_template has been_depracted, so in order to use it as before you need to add:
gem 'rails-controller-testing'
to your Gemfile.
Original discussion why using assigns is a bad idea.
If you want to verify that a certain variable has been assigned in your tests then you can use following statement in your test. This will check whether your #user variable in controller has some value in it or not.If #user has some value in it then the test will pass otherwise it will fail
assert_not_nil assigns(:user)
And then you can run following command to run your test in terminal
ruby -I test test/integration/your_test_file_name.rb -n test_name

Resources