Reputation: 3568
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?
Upvotes: 1
Views: 548
Reputation: 37607
[Repeating some of what others said for the sake of completeness:]
A good approach known as BDD (see bdd) works outside-in by
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.)
Upvotes: 2
Reputation: 101811
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.
Upvotes: 2
Reputation: 11235
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.
Upvotes: 1