I just start learn Ruby on Rails. When I research about RSpec test, I saw a recommend link about RSpec Mocks. However I don't know about the advantages of RSpec Mocks and how to use it. So can anyone summary about this.
rspec-mocks is a test-double framework for rspec[RSpec is a 'Domain Specific Language' testing tool written in Ruby to test Ruby code] with support for
method stubs, fakes, and message expectations on generated
test-doubles and real objects alike.
rspec-mocks helps to control the context in a code example by letting you set known return
values, fake implementations of methods, and even set expectations that specific messages
are received by an object.
RSpec Mocks Installation References
RSpec Mocks Reference #1
RSpec Mocks Reference #2
Reference #3
Mocks help you to keep your tests clean. I'd recommend to start with integration tests (like cucumber for example). There you do not use mocks (unless perhaps something like WebMock, to capsulate your application from the outside world). You start with rspec unit tests as soon as you recognize the code gets complex, that you are going to write to make your integration test green. Now you capsulate your models from other models and your controllers from models with mocks. So the code you are going to write, to make rspec tests green, is not relying on other things. With mocks you just specify the bahaviour of all related stuff and it will behave as you defined. Of course you still have to test, that this other stuff will really fullfill these expectations. But when later implementation of some change request will break one model - really only the tests of that model will break. And everything that is related will still work, since the mocks behave, as defined. This way you find much easier and faster the real problems.
Another advantage of course is, that you get along with much less database pollings.
I learnt Rspec and cucumber with the Rspec Book. It helped me to get the feeling about the advantages of the mocking approach.
Related
I am learning RSpec and Cucumber, so that I can write tests for our Rails website at work.
While learning, I used a book called "The RSpec Book: BDD with RSpec, Cucumber and Friends". During this, RSpec was used for granular tests and Cucumber was used for overall usability tests.
The book used a simple CLI game as an example.
Now I am heading into a web environment, wondering what is the mentality of testing in a web environment.
I already know that I will be writing spec tests for my models and controllers.
I assume that where Cucumber comes in is full feature tests which will use both controller and model to accomplish.
Please correct me if I'm wrong, but let's say there are User, Post and Likes models.
Each of these would have a model spec + however many controller specs.
Then I would write a single feature test as:
Feature: liking a post
As a user of abc.com
I want to like a post
So that I can show my friends
Where I would log in as someone, find a post and like it?
Anyone with experience mind sharing the angle of approach on testing with these tools on a Rails application?
Let's say I had to implement the situation above, would you start by fleshing out the feature test, write the model specs, then write the controller specs and then write code?
[Repeating some of what others said for the sake of completeness:]
A good approach known as BDD (see bdd) works outside-in by
test-driving a feature with an acceptance test (which in the Ruby world is usually written as a Cucumber feature or RSpec feature spec)
test-driving details with unit tests to express detailed requirements if necessary.
Using this method to test-drive a feature of a Rails project, you'd first write an acceptance test and then implement it, which would bring into existence the route(s), view(s), controller(s) and model(s) needed for the feature. Since you're test-driving, you haven't written any code that isn't fully tested by the acceptance test and you don't need any controller, model, etc. specs yet. You might then start over with another acceptance test, or you might want to test-drive some detailed requirements using lower-level specs.
Suppose that your acceptance test tested that a user's full name is shown on the page and you want to be sure that it looks correct when a user hasn't entered their last name. If User#full_name returns the user's full name, you could just write a model spec for that method rather than writing another acceptance test.
In my experience well-factored Rails applications written using BDD need few or no controller specs, since controllers should delegate to models and other classes as much as possible and so are completely tested by acceptance tests. Lots of details are best tested in model specs.
Regarding how to write acceptance tests, I need to disagree with others' statements about Cucumber, or at least give a warning: I've seen Cucumber result in a readable, maintainable acceptance test suite for a large production application, and RSpec feature specs result in an bloated, unmaintainable acceptance test suite, so don't dismiss Cucumber, or the needs that it addresses:
Don't be fooled by the idea that human-readable acceptance tests are only for your product owner or customer; they're absolutely valuable for engineers, allowing you to think at a high level when appropriate instead of getting lost in the noise of code. The larger the project, the more you'll care.
Cucumber nicely separates acceptance-level descriptions of steps in tests from implementations of those steps (CSS selectors, ActiveRecord queries, etc.), almost automatically making those steps reusable. With RSpec feature specs, it's all up to you; be prepared to come up with your own system of extracting detail into methods whose names make it clear what the user-level point of each step is. (I don't mean page objects; they're a level of detail below what I mean, and are useful in both Cucumber and RSpec feature specs.)
The role of cucumber here is as an acceptance specs. They test the behavior of your application as a whole from the view point of a user. They cover the entire stack from routes to controllers, models and views.
In BDD you often use acceptance testing not just as frosting on top of the cake as in TDD but rather as a driving force in what is called outside in development.
In outside in development you would create a failing specification which details the user story before setting up the routes, controllers or any of the underpinnings.
Compare this to the traditional TDD approach where you start by breaking things down into their smallest units to get a fast red - yellow - green cycle. And then you would start stacking the block on top each other with tests that gradually cover more and more of the stack.
However this does not mean that acceptance specs are the only useful form of specs - they have a rather large overhead and it can be difficult to test edge cases. Thus using just Cucumber is not a very attractive solution.
First this is more opinion than anything else, but here goes. Generally, with TDD, I try to work from the outside in (outside-in-development). In other words, write feature specs, then controller specs (if desired), and then model specs. The rationale here is that your feature tests are the user-facing aspect of your application. Focusing on high-level user behavior up-front helps mitigate time wasting and building things you don't need. Additionally, if you start with feature tests, you can mock/stub lower levels of your application, such as model interactions in your controller, as necessary, which yields faster tests that are well isolated.
Finally, and again, this is more of an opinion -- I think it's overkill to use both Cucumber and RSpec. RSpec works fine, handles unit testing better, and is easier to maintain than Cucumber. Every time I've created a project using both, I eventually scrap Cucumber and just stick to RSpec.
Specifically, for testing user login, I'd recommend including both using the Devise login helpers which makes logging in users faster and easier https://github.com/plataformatec/devise#test-helpers.
I have started writing tests using Rspec for a really old project. The models which i am testing are all ActiveRecords(backend is Oracle).
I have read some blogs that say we should use mocking and stubbing/fixtures/factory girl over firing an actual sql.
I am confused. I will have to stub a lot of methods and create lot of objects. Is this a good practice ?
When you are testing a model, it's good to let your tests integrate against the database. That is, don't try to mock out the ActiveRecord stuff, and just use a model object. FactoryGirl and Fabrication are both just convenient shortcuts to building real model objects, and they are best practises when it comes to testing ActiveRecord models.
Since this is legacy code, I would suggest not mocking or stubbing too much in the old code, because isolation only works if each component is tested in isolation.
However, when writing code with TDD, mocking and stubbing has many benefits:
Gives you fine grained tests (if a method breaks, your tests tell you which one)
Your tests run much faster, and thus your TDD cycle is shorter
Lets you make assertions about how your code interacts with other objects
If you have to stub and mock other models excessively to isolate one model, it is usually a good sign that your code is too highly coupled and deserves a refactor
Normally you would use stubs, then you can run tests without loading AR, and they will run a lot faster.
Personally I believe that testing fake data is no test... Maybe in a development environment doing TDD... Maybe..., but for a test environment it should be as close to the real thing as possible.
This is of course my opinion and may not be the current school of thought.
I have an application which having at least 50-55 models with on an average 15 methods each.
Is it possible & is it make sense to cover all the methods (including very complex methods) using rspec & rcov ?
I also have following queries
Is Rspec also useful for the Controllers, helpers & views? Or cucumber, shoulda are more useful?
Will rspec help me to reduce redundancy?If yes, how?
will rspec is useful for continuous requirement changing applications?
It certainly is possible to cover all methods with tests, even more if you start by writing the tests before, which usually lead to a leaner application on the long run. On the other hand having a 100% test coverage does not ensure that your application code quality is better or that your team is more productive. The only thing it might ensure is that your application has less flaws and that you won't break anything in case of refactoring, and then comes the argument against covering all methods with tests:
More often than not you'll be refactoring and maintaining code, which usually involves adding new methods and getting rid of other methods.
I'd say that it's good to have tests for all public methods called by other objects or views, controllers, helpers, etc. And test for all the relevant API methods, but it's far from necessary to have every single method tested.
On the other hand it will depend on your application itself more than on an abstract conversation about it.
You'd have to ask yourself if it's worth it, what value does it add, etc, and if it makes sense, go for it. Whether you choose to do it in pure rspec, or use cucumber, shoulda, capybara, etc
A Rails/tool specific version of: How deep are your unit tests?
Right now, I currently write:
Cucumber features (integration tests) - these test against the HTML/JS that is returned by our app, but sometimes also tests other things, like calls to third-party services.
RSpec controller tests (functional tests), originally only if the controllers have any meaningful logic, but now more and more.
RSpec model tests (unit tests)
Sometimes this is entirely necessary; it is necessary to test behavior in the model that is not entirely obvious or visible to the end-user. When models are complex, they should definitely be tested. But other times, it seems to me the tests are redundant. For instance, do you test method foo if it is only called by bar, and bar is tested? What if bar is a simple helper method on a model that is used by and easily testable in a Cucumber feature? Do you test the method in rspec as well as Cucumber? I find myself struggling with this, as writing more tests take time and maintaining multiple "versions" of what is effectively the same behaviors, which makes maintaining the test suite more time intensive, which in turn makes changes more expensive.
In short, do you believe there is there a time when writing only Cucumber features is enough? Or should you always test at every level? If you think there is a grey area, what is your threshold for "this needs a functional/unit test." In practical terms, what do you do currently, and why (or why not) do you think it's sufficient?
EDIT: Here's an example of what might be "test overkill." Admittedly, I was able to write this pretty quickly, but it was completely hypothetical.
Good question, one I've grappled with recently while working on a Rails app, also using Cucumber/RSpec. I try to test as much as possible at every level, however, I've also found that as the codebase grows, I sometimes feel I'm repeating myself needlessly.
Using "Outside-in" testing, my process usually goes something like: Cucumber Scenario -> Controller Spec -> Model Spec. More and more I find myself skipping over the controller specs as the cucumber scenarios cover much of their functionality. I usually go back and add the controller specs, but it can feel like a bit of a chore.
One step I take regularly is to run rcov on my cucumber features with rake cucumber:rcov and look for notable gaps in coverage. These are areas of the code I make sure to focus on so they have decent coverage, be it unit or integration tests.
I believe models/libs should be unit tested extensively, right off the bat, as it is the core business logic. It needs to work in isolation, outside of the normal web request/response process. For example, if I'm interacting with my app through the Rails console, I'm working directly with the business logic and I want the reassurance that methods I call on my models/classes are well tested.
At the end of the day, every app is different and I think it's down to the developer(s) to determine how much test coverage should be devoted to different parts of the codebase and find the right balance so that your test suite doesn't bog you down as your app grows.
Here's an interesting article I dug up from my bookmarks that is worth reading:
http://webmozarts.com/2010/03/15/why-not-to-want-100-code-coverage/
Rails has a well-tested codebase, so I'd avoid re-testing stuff that is covered in those steps.
For example, unless it is custom code, it is pointless to test the results of validations at unit and functional levels. I'd test them at the integration level though. Cucumber features act as specifications for your project, so it is good to specify that you need a validation for x and y, even if the implementation is a single line declaration in the model.
You usually don't want to have both Cucumber stories and RSpec controller specs/integration tests. Pick one (generally Cucumber is the better choice, except for certain special cases). Then use RSpec for your models, and that's all you need.
I test complex model/lib methods with rspec then the main business logic in web with cucumber, so I'm sure that the main features of the web will work 100%, then if I got more time and resources I test everything else.
Its easier to write simple specs for simple methods. Its much easier than writing cukes.
If you keep your methods simple - and keep your specs simple - by testing only the logic inside that method - you will find joy in unit testing.
If anything is redundant its cucumber tests. If you have well tested models and lib your software should work.
The purpose of Cucumber is not to run integration tests. Cucumber, an in general BDD, works as a communication platform, a way to improve the "talk" inside a big team of developers an non-developers that are developing big and complex software. BDD is very useful to communicate a model an its domain at the same level to everybody in the team, even if they don't know anything about computers.
If that is not your scenario, don't use cucumber, because you don't need it. Use rspec and capybara to test your JS code and your integration tests.
I am finding holes in my coverage because I have been mocking my models in controller examples. When I remove a model's method upon which a controller depends, I do not get a failure.
Coming from TDD in statically typed languages, I would always mock dependencies to the object under test that hit the database to increase speed. I would still get failures in the above example, since my mocks subclassed the original object. I am looking for best practices in a dynamic language.
Thanks.
UPDATE:
After getting a lot of conflicting opinions on this, it seems it boils down to which philosophy you buy into.
The Rspec community appears to embrace heavily stubbing dependencies to achieve isolation of the object under test. Acceptance tests (traditionally known as integration tests ;) are used to ensure your objects work with their runtime dependencies.
The shoulda / Test::Unit community appears to stay away from stubbing as much as possible. This allows your tests to confirm your object under test actually works with its dependencies.
This video summarizes this nicely: http://vimeo.com/3296561
Yes, in your controller examples, mock your models. In your model examples, test your models.
If you're using Mocha, the following should do it.
Mocha::Configuration.prevent(:stubbing_non_existent_method)
While writing unit tests, the whole aim should be test that unit only. Consider Model as one unit and cover it separately. Change in Model should not directly impact unit test coverage of controller.