Okay, let me clarify that title first. I, as most of you, have two sets of tests for my Rails application: rspec and cucumber. rspec heavily focusses on testing models and business logic while cucumber focusses on testing the entire application stack and user interaction.
The problem is that as your app grows, your test set grows - and so does the time it takes to run those tests.
_This post is inspired by [Corey Haines](http://coreyhaines.com)' talk at [Arrrrcamp](http://arrrrcamp.be) (Oct 2011) and my own experience with writing fast specs._
## Red - Green - Refactor
If you do TDD/BDD you most likely follow the Red-Green-Refactor pattern:
1. Write one test, and see it fail (red)
2. Write the most minimal implementation to satisfy that test, and see it pass (green)
3. Refactor your code to look/perform better (refactor)
4. Repeat
But what if your test suite takes >30 seconds to run. You write a test, then wait 30 seconds to see the test fail. You then write the simple implementation, wait 30 seconds. Oops, you made a typo - fix it, wait 30 seconds. Now it passes. Refactor, again wait 30 seconds.
I think this scenario is very familiar for many rails developers.
## Take a closer look
So, let's take a closer look at a real-world example.
This is a `Post` model, it `belongs_to` and author and it can give you a summary of an article by returning the text above a '~' marker.
This means that running the actual spec took 0.05s, but running the entire command took 10 seconds. What is slowing us down?
## Dependencies
As you see in the spec above I use `FactoryGirl.build` instead of `FactoryGirl.create` to prevent interacting with the database. I do this because hitting the database slows down your test.
I removed the database dependency in order for my test to run faster.
What other dependencies are there that could be removed in order to test the summary functionality?
Any idea?
Yes!
Rails.
## Rails is a dependency to your app
You have a Rails-app. But Rails is not your app, it's a dependency, just like the `pg` and `haml` gems are dependencies.
Loading the entire Rails stack takes quite some time. And just like with the database dependency we must ask ourselves: do we really need Rails to perform this test?
There are a lot of scenarios where the answer to that question is _NO_.
## Specs without Rails
This may seem a bit weird at first, but let's take another look at the `Post` model:
The `summary` method does not interact with the `Post` model at all, except that it access the `body` attribute. But the `body` attribute is just a `String`.
So, if we wanted to test the `summary` method and remove all Rails dependencies, we'd have to remove ActiveRecord.
That looks good! Note that this spec _does not_ include `spec_helper`. `spec_helper` is responsible for loading up your test environment, which normally includes all your app dependencies, including Rails.
## Your new Post model
The `Post` model should also be updated, of course to utilise this new class.
The spec for `Post` should also be changed. Since we already have tested that `MyApp::Summary#for` returns the right summary for a given text and delimiter, all we have left to do is make sure that `Post#summary` calls it correctly.
The files above are located in `fast_spec` and `app/logic`. I do this because I want to separate my fast_specs so I can run them independtly from my normal specs.
That's your same spec, down from about 10 seconds to 0.5 second.
## The big picture
By now you have seen that you can extract business logic into a seperate class. You've also seen that you can write tests that don't depend on Rails and run amazingly fast.
Of course you ask, how does this relate to normal RSpec and Cucumber tests?
My opinion is that your fast_specs test business logic that does not relate to anything Rails specific, like making calculations, processing text, et cetera.
When you make changes to your business logic, you can test is very quickly. This shortens your TDD cycle and allows you to focus more on the task at hand (instead of waiting for your tests).
RSpec tests are there to test integration with your dependencies like Rails. This is the place where test scopes and mailers.
Cucumber still has its place to test user interaction with your app. Can a user still click the 'Order' button and get the proper response from our app.
RSpec and Cucumber will now be ran less often. Maybe only before you commit code - or maybe have your CI run them for you?
## Added benefit - Design
An added bonus of TDD is that your tests dictate the design of your app. By using fast_spec you force your business logic into separate classes. This makes them even more re-usable than normal Rails models.
Your ActiveRecord models now become cleaner and are more a _configuration of Rails_ than anything else.
By doing this your app will become way more maintainable, easier to test, faster to test and your code will be more re-usable. What's not to like?
## Where to go from here?
As Corey Haines put it:
> Try to extract one single method from your app into a fast_spec. Just one. When you have that one spec running so fast it's easy to add more.
This would also be my advise to you. Try to extract one piece of functionality from a model into a fast_spec. It may be difficult at first, but try it and see the results.