Rails Fixtures vs. Mocks - ruby-on-rails

I'm developing a Rails app, and I was just talking with my colleague that we have a mix of fixtures and mocks in our tests, which we're doing using cucumber and Rspec. The question would be: when should each one be used?

I would use a mock object when using the real object is impracticable/not necessary. Lets say for example you need to call some remote API such as an address finder via zip code. You would probably want to mock the object so the calls on it aren't actually made each time you run your tests. There are other reasons too such as improving speed, asking for data that changes where you need an exact response or perhaps it doesn't exist yet. It allows you to test things in isolation as you can determine that when you call these methods on this mock object you will get this back and you don't actually need to run the code as for this test it's not important.
If you use fixtures you will have a real object and the methods etc will be called and their code run, unless of course you stub the methods out, which is something for another question.
Hope that helps a little. There is a good peepcode (http://peepcode.com/products/rspec-mocks-and-models) on mocking and stubbing, maybe check it out.

Related

What's wrong with Rspec, FactoryGirl and real sample data?

I've been leaning some of RoR, and when I got to TDD, stuff started to get more complicated. At some point of my App, I thought it would be better to run my tests over the real data.
Real Data vs Sample Data
Searching the web, I found that tests were not meant to run over real data, but over sample data. But yet I couldn't agree with that.
Let's supose my app had an Alias System. So when you access a random url it figures out what that fragment wants and redirects to the proper canonical url. And let's add that an alias dictionary is stored in some models. How would we test agains that dictionary? Hard code spec files for every alias/keyword?
Sticking with real data
The first two things I've realized, yet very unsurely, is:
Rspec testing environment wouldn't access development model's data.
FactoryGirl rules over my testing database, so it's not my option to populate it.
The best solution I could figure out, as the complete newbie I am, is that I could create some classes in spec/support folder and call them inside my factories so as to get that real data. Those classes have a short sample of my real database info, nested, and so my test can go 'real'.
What can pros around suggest to improve it?
I think you may want to look into building a seeds.rb file to populate your databases. This is usually used to initialize the development database so it can be used in your app (and queried in the rails console), but you can use it to seed your test database as described in this answer.
You certainly should not use your development database for testing. You can either seed the test database, or create factories that reflect various scenarios.
FactoryGirl rules over my testing database, so it's not my option to populate it.
You can use more than one factory to represent a business entity, depending on the scenario under test. FactoryGirl makes this easy by allowing you to nest factories. You can define a factory with a basic set of valid attributes and use that in unit tests. For integration (feature) tests, you can use a nested factory that expands on the basic attributes to implement a particular scenario. You can have as many variations of these implementation-specific factories as you need.

Controller tests bleeding to models?

I am writing some tests with RSpec (tests and not specs, the code was untested until now) and have stumbled upon an uncertainty...
I want to know whether a controller is calling the model's methods properly and I am divided between the possibilities:
test the controller with stubbing the model method (I won't know if the model method actually exists or accepts the arguments given)
leave the model method unstubbed and risk having my controller tests bleed into model test territory (and also make them slow cause of DB access and costly methods)
write multiple controller tests, each of them leaving unstubbed one model method (still slow as hell but at least it's verbose)
Is there a correct answer on this?
You could stub the model method if you want, but in general you shouldn't check in controller test that particular method of a model was called you should check controller's response content. Don't forget about black box metaphor.
I suggest you test your controllers without stubbing your models. Do not care about the speed of the tests when it hits the database. I assume you want to have the database also tested, and having a correct program is more important than the speed of your tests, isn't it?
Consider the functional tests as another layer around your unit tests, not as something that is isolated from your models. Your unit tests (models) ensure that some model methods work as expected, and then your controller tests ensure that the controller is able to use these methods, and they work as the controller expects.
As iafonov said, do not focus on the model's methods in your controller tests. Assume that if your controller is able to give you the correct response, then your model apparently works as expected.
Of course, some people have different point of view. I do not claim that my suggestion is the best. It just works for me, and I consider it being right. A lot of people suggest that you should test your controller in isolation from models, but how do you ensure then that there is no discrepancy between your stubs and your real implementation?
I'm pretty late to the party. But agree strongly with solnic and disagree with Arsen7.
Think about it:
If you are using vanilla active record methods, e.g. MyModel.find_by_id(123) you can safely stub that because AR is already well tested, no need to his the database for those.
If you are calling a custom method you defined on the model, e.g. MyModel.foo(param1, param2) then you should still mock/stub it because you should have a test for it in your MyModel spec.
The only downside to stubbing model methods is that sometimes if you change the interface for a method your controller will be ignorant of that change and the test will still pass. Typically either integration or manual tests will uncover the problem. If you are working on a large project speed quickly becomes an issue and avoiding the perf hit from interacting with the database is more than worth an occasional head scratch imho.
With good model/unit tests it's recommended to stub models in controller specs (and it is obviously recommended to have good model/unit specs heh). Full stack should be covered by requests/acceptance specs anyway. I like to treat controller specs as 'unit specs' for controllers. With skinny controllers stubbing model in specs should be easy and should not touch any implementation details.

Should I really test controllers?

I'm trying to get the best codecoverage/development time result
Currently I use rspec+shoulda to test my models and rspec+capybara to write my acceptance tests.
I tried writing a controller test for a simple crud but it kinda took too long and I got a confusing test in the end(my bad probably)
What`s the best pratice on controller testing with rspec?
Here is a gist on my test and my controller(one test does not pass yet):
https://gist.github.com/991687
https://gist.github.com/991685
Maybe not.
Sure you can write tests for your controller. It might help write better controllers. But if the logic in your controllers is simple, as it should be, then your controller tests are not where the battle is won.
Personally I prefer well-tested models and a thorough set of integration (acceptance) tests over controller tests any time.
That said, if you have trouble writing tests for controllers, then by all means do test them. At least until you get the hang of it. Then decide whether you want to continue or not. Same goes for every kind of test: try it until you understand it, decide afterwards.
The way I view this is that acceptance tests (i.e. Cucumber / Capybara), test the interactions that a user would normally perform on the application. This usually includes things like can a user create a specific resource with valid data and then do they see errors if they enter invalid data. A controller test is more for things that a user shouldn't be able to normally do or extreme edge cases that would be too (cu)cumbersome to test with Cucumber.
Usually when people write controller tests, they are effectively testing the same thing. The only reason to test a controller's method in a controller test are for edge cases.
Edge cases such as if a user enters an invalid ID to a show page they should be shown a 404 page. This is a very simple kind of thing to test with a controller test, and I would recommend doing that. You want to make sure that when they hit the action that they receive a 404 response, boom, simple.
Making sure that your new action responds successfully and doesn't syntax error? Please. That's what your Cucumber features would tell you. If the action suddenly develops a Case of the Whoops, your feature will break and then you will fix that.
Another way of thinking about it is do you want to test a specific action responds in a certain way (i.e. controller tests), or do you care more about that a user can go to that new action and actually go through the whole motions of creating that resource (i.e. acceptance tests)?
Writing controller tests gives your application permission to lie to you. Some reasons:
controller tests are not executed in the environment they are run in. i.e. they are not at the end of a rack middleware stack, so things like users are not available when using devise (as a single, simple example). As Rails moves more to a rack based setup, more rack middlewares are used, and your environment deviates increasingly from the 'unit' behaviour.
You're not testing the behaviour of your application, you're testing the implementation. By mocking and stubbing your way through, you're re-implementing implementation in spec form. One easy way to tell if you're doing this; if you don't change the expected behaviour of url response, but do change the implementation of the controller (maybe even map to a different controller), do your tests break? If they do, you're testing implementation not behaviour. You're also setting your self up to be lied to. When you stub and mock, there's no assurances that the mocks or stubs you've setup do what you think they do, or even if the methods they're pretending to be exists after refactoring occurs.
Calling controller methods is impossible via your applications 'public' api. The only way to get to a controller is via the stack, and the route. If you can't break it from a request via a url, is it really broken?
I use my tests as an assurance the my application is not going to break when I deploy it. Controller tests add nothing to my confidence that my application is indeed functional, and actually their presence decreases my confidence.
One other example, when testing your 'behaviour' of your application, do you care that a particular file template was rendered, or that a certain exception was raised, or instead is the behaviour of your application to return some stuff to the client with a particular status code?
Testing controllers (or views) increases the burden of tests that you impose on yourself, and means that the cost of refactoring is higher than it needs to be because of the potential to break tests.
Should you test? yes
There are gems that make testing controllers faster
http://blog.carbonfive.com/2010/12/10/speedy-test-iterations-for-rails-3-with-spork-and-guard/
Definitely test the controller. A few painfully learned rules of thumb:
mock out model objects
stub model object methods that your controller action uses
sacrifice lots of chickens.
I like to have a test on every controller method at least just to eliminate stupid syntax errors that may cause the page to blow up.
A lot of people seem to be moving towards the approach of using Cucumber for integration testing in place of writing controller and routing tests.

Mocks and Stubs

I really don't understand what Mocks and Stubs are. I want to know when, why and how we use Mocks in our test cases. I know that there are good frameworks out there for Mocks and Stubs in Ruby on Rails, but without knowing the purpose, I'm reluctant to use them in my app.
Can you please clarify about Mocks and Stubs? Please help.
My very simplified answer is:
mocks are objects that have a similar interface as something else
stubs are fake methods and return a specific answer
With both we are trying to achieve the same thing: we want to test a specific unit (model/view/controller/module) in isolation. E.g. when we are testing the controller, we do not want to test our model, so we use a mock. We want to make sure the correct methods are called, e.g. find. So on our mock, we have a stub that will return something predefined, without actually going to the database.
So we test for expectations: the methods that we expect to be called (on other units), without actually calling them. The test of that specific method, should have been covered in its own test.
According to Fowler's article mocks are not stubs, stubs are fake methods independent from outside calls, while mocks are fake objects with pre-programmed reactions to calls.
Mocking is more specific and object-related:
if certain parameters are passed, then the object returns certain results. The behavior of an object is imitated or "mocked".
Stubbing is more general and method-related:
a stubbed method usually returns always the same result for all parameters. The behavior of a method is frozen, canned or "stubbed".
Mocks are used in interaction-based testing to verify behavior. With a mock, you can assert that the method under test called another method. For example, I might want to make sure that a controller object calls a repository to get some data.
Stubs are used in state-based testing to set up a certain application state. Unlike mocks, you don't worry whether the call was made or not. For example, if you were testing some repository code, you might want to set up a stub method to make sure that the repository correctly handles the case when the database connection is closed.

Rails RSpec, how does it apply in such a case?

i'm daily in the process of learning new things about Rails (started learning 2 and now migrating to 3 concepts). As a project with Rails, i'm coding a browser game. Till now, i've been using fixtures to load data to my database and i've creating a custom task to recreate the db, load fixtures etc every time i need to. I have to say that i like this approach because i can easily define my monsters with weapons, bonuses etc through active record associations in features.
However, i see that people use a testing environment like RSpec for that kind of things. Although i see that RSpec is used as a language to define proper behaviour, i don't clearly see how it could help me. But since i like to do things the correct way, i'm pretty sure that there is much more for me to understand and read about it.
Therefore, i would like to ask for a solid example of how RSpec could be helpful. For instance, let's say that a user creates an alliance. Through my code, i'm checking whether this user already has an alliance, whether an alliance with that name exists, whether he has the money to create this alliance and more. Where would RSpec fit here ? What would a nice usage example be ?
Moreover, is fixtures done using RSpec in another way ?
I already know that Rails has many great programmer conveniences and i would like to harvest this one as well. But i'm still ignorant about RSpec. That is why i would appreciate some useful insight. Thank you :)
Rspec is a testing framework. It allows you to write automated pieces of code that verify that your code is actually working. For example, you could write a test to make sure that no two alliances have the same name:
describe Alliance do
it 'should not have the same name as another alliance' do
first = Alliance.create :name => "Test Name"
second = Alliance.build :name => "Test Name"
second.should_not be_valid
end
end
This code would then verify that no two alliances can have the same name - it's a way of testing that your code is actually working.
Fixtures, Factories, Mocks and Stubs are all ways of creating temporary data that can be used in tests. RSpec can use Fixtures, but it doesn't require them either. If you want to load test data into your database you can do this in whichever method best suits your needs to perform tests.
Some other testing frameworks are Cucumber, TestUnit, MiniTest and Shoulda. You should be using one already to write tests for your code. You can also read up on the others to find out which framework best suits your needs.

Resources