I am trying to test a controller with RSpec but am having a problem because a function in the controller requires a database.
the line of code in the controller looks something like:
#myallresources = Myrsources.all
where Myresources just inherits from ActiveRecord::Base
however, because there is no database, there is nothing to load and #myallresources is just an empty array, causing the test to fail. Is there a way to connect to a database while running the rspec?
I am very new to RSpec and rails so any help would be very appreciated. Thanks.
You shouldn't use a database connection in your controller specs.
Check the section about database isolation on this page http://rspec.info/rails/writing/controllers.html
Basically you have to mock or stub your ActiveRecord models, as those should be tested separately in the models specs. Here's a simple example using mock_model:
before do
mocks = (1..3).map { mock_model(MyResource) }
MyResource.should_receive(:all).and_return(mocks)
end
Put this inside the same block where reside the describe definition testing for the actions that use MyResource.all.
You can find good explanation of mocks and stubs in following links:
http://relishapp.com/rspec/rspec-rails/v/2-5/docs/mocks/mock-model
http://relishapp.com/rspec/rspec-rails/v/2-5/docs/mocks/stub-model
Related
I'm fairly new to using RSpec, so there's a lot I still don't know. I'm currently working on speccing out a section of functionality which is supposed to run a script when a button is pressed. The script is currently called in a controller, which I don't know if there's a good way to test.
I'm currently using
expect_any_instance_of(ConfigurationsController)
.to receive(:system)
.with('sh bin/resque/kill_resque_workers')
.and_return(true)
in a feature spec and it works, but rubocop is complaining about using expect_any_instance_of and I've been told to only use that method if there was no better way.
Is there any better way to test this? Like is there a way to get the instance of the controller being used, or a better kind of test for this?
A better pattern would be to not inline the system call in your controller in the first place. Instead create a seperate object that knows how to kill your worker processes and call that from your controller. The service object pattern is often used for this. It makes it much easier to stub/spy/mock the dependency and make sure it stops at your application boundry.
It also lets you test the object in isolation. Testing plain old ruby objects is really easy. Testing controllers is not.
module WorkerHandler
def self.kill_all
system 'sh bin/resque/kill_resque_workers'
end
end
# in your test
expect(WorkerHandler).to receive(:kill_all)
If your service object method runs on instances of a class you can use stub_const to stub out the new method so that it returns mocks/spies.
Another more novel solution is dependency injection via Rack middleware. You just write a piece of middleware that injects your object into env. env is the state variable thats passed all the way down the middleware stack to your application. This is how Warden for example works. You can pass env along in your spec when you make the http calls to your controller or use before { session.env('foo.bar', baz) }.
Background: I am unit testing a game server which is built upon rails 4.1.1 and separate socket.io/node.js for socket messaging. Messages from node.js to rails are going through RESTful http requests.
Single test case runs as follows:
(1) rake unit test --> (2) rails controller --> (3) node.js/socket.io --> (4) rails controller
Problem description: Some DB entries are created with ActiveRecord at step (2), then upon receiving a socket message at step (3) node.js sends HTTP request back to rails controller and finally(!!) at step (4) rails controller tries to access DB entries from step (2), but TEST DB contents are empty at this point.
Question: It seems like desired behavior of rake to cleanup TEST DB, but how can I persist TEST db across test cases and prevent such problem?
Thanks in advance
You should prepare and send request to node app inside a test and assert response there.
But it's not a good practice. The better solution would be HTTP mocks (like webmock gem). This approach will save lots of time in the future.
Luckily, I figured out the solution.
By default, rake is wrapping all tests in separate DB transactions and rolls back on cleanup. Moreover, whatever requests/queries are coming outside of TestCase are not included in transaction and not visible inside the test case.
To avoid such behavior, we have to disable transactional fixtures in test/test_helper.rb
class ActiveSupport::TestCase
self.use_transactional_fixtures = false
end
As downside, we have to cleanup test db manually. So #Alexander Shlenchack points out to avoid such practice in the first place and use http/socket mocks in future.
Here is brief summary http://devblog.avdi.org/2012/08/31/configuring-database_cleaner-with-rails-rspec-capybara-and-selenium/
And related question Rails minitest, database cleaner how to turn use_transactional_fixtures = false
I am a big fan of FactoryGirl, but have never understood the ".build_stubbed" method and would like to incorporate stubbing/mocking into my TDD. Can someone help me with the basics of what kind of stubbing I can do with FactoryGirl? Should I start using Mocha or another similar GEM to handle the mocking/stubbing or is any of this included in the Rails 4 default MiniTest?
The factory girl command build_stubbed means that the object is created (and also all its associated objects) but no objects are inserted into the database. You should use this if you want faster tests and do not need to have the objects in the database.
This means that the command does not have to do much with stubbing or mocking.
I myself have only experience with Mocha and can say that it very easy to use it for stubbing and mocking.
For stubbing out a command (e.g. of the object Person)
person = Person.new
person.stubs(:name).returns('Robert')
The obove example creates an instance of the person and stubbes out the method name to always return 'Robert'.
For mocking out the same command
person = Person.new
person.expects(:name).returns('Robert')
The above does the same as stubbing out the method. With the only difference that now the test fails if the method name is not called exactly once.
Does anyone know how to test page_caching in Rails using RSpec without having to check to see if the cache file has been created for each request? Something more like Controller.performs_page_caching(:action).should be_true?
I've tried looking over the net, but I haven't found anything that works.
I have come up with a solution. You override the caches_page class method for the ApplicationController class and setup an after filter which sets a header 'x-page-cached' to true. Then in your test scripts include a macro for page_cached? which will check to see if response.headers['x-page-cached'] is true or not. Only do this for the test and development environments.
Seems like integration test. For example you could try write request spec and count somehow number of db queries.
I'm currently using ruby 1.9.2 and rails 3 and I'm in the middle of rspec testing. Basically, I have a function that is called by a before filter in the application controller such that it obviously gets run every time a controller action is made anywhere on my site. For testing purposes, I'm writing tests for a different controller but my actions do not set off my before filter function call. Is there any way to specifically call functions from a specific controller within rspec tests? I can't post the code online, so no use asking for it :P.
Thanks
Inside an it or before(:each) block in a controller spec:
controller.send( :your_method_name )
And your function is going to be called.