— Hieroglyphs — 3 min read
“Test-driven development” refers to a style of programming in which three activities are tightly interwoven: coding, testing (in the form of writing unit tests), and design (in the form of refactoring).
If you've written a functioning application and didn't write tests, you've practiced in "Error Driven Development". As the name suggests, you've written of code, and relied on the errors in your terminal or browser to know if it was written properly.
There is nothing wrong with Error Driven Development per se. However, as your app scales (grows), and accumulates hundreds of migration files, endless endpoints / routes, and countless interwoven models, relying on errors as they arise is simply not feasible.
There are many reasons why TDD is important. I'll rattle off a few like the good TDD evangelist that I am. As previously mentioned, testing helps to maintain some semblance of order as your application scales. Additionally:
It pushes you to write cleaner code!
I think back to middle school and having to write book reports (or any paper in school, really). First you write an outline, then the paper. Writing an outline first generally helped in keeping the execution of the paper, and it's content more organized. The same can be said of Test Driven Development.
Safer refactoring.
Let's suppose you step away from a part of the app for a few months. Upon return, you've identified code you can refactor. Tests will aide in keeping your refactor, reasonable.
Living Documentation!
In my humble opinion, this is the greatest benefit to writing tests. Tests act as documentation for your application. If I arrive to unfamiliar code and I'm curious as to how this area of the application might behave, I can look at the test(s) to get an idea.
Time. It takes time and patience to plan and craft well written tests. However the time spent on writing tests upfront, saves so much time in the long run. So really there are no cons; WRITE TESTS!
TDD requires a minimum of two styles of tests to successfully cover an application: Unit Tests and Integration Tests.
In the essence of brevity, we will explore simple Unit Testing in Rails, and I will save Integration Tests for a subsequent post.
If you are a Flatiron student and reading this, you are in luck. You have an entire curriculum worth of tests for examples of well written tests. If you are not a Flatiron student and need some examples of tests, check out opensourcerails.com. Quite frankly, whenever I am in search of examples of well written code, I look at open source projects.
I am assuming that you are working with a Rails app that does not have a testing unit already installed. If you are starting from scratch, run rails new your_app_name -T
. The -T
flag will tell Rails to skip adding the default testing suite (I believe its name is minitest).
If you
gem 'rspec-rails', '~> 4.0.2'
1group :development, :test do2 gem 'rspec-rails', '~> 4.0.2'3 end
Update Gemfile.lock
Run $ bundle install
to update your gemfile.lock.
Generate necessary files and directories
Run $ rails generate rspec:install
This will generate the necessary files and directories necessary for RSpec.
1create .rspec2 create spec3 create spec/spec_helper.rb4 create spec/rails_helper.rb
.rspec
file and add --format documentation
to it. That's all. Save and close the file, let's continue on our merry little way. And thats it! For all intents and purposes RSpec is installed in your application. So like, now what do we do? Well we can test a bunch of things -- Did you set up your models correctly? Are necessary routes available? How about controllers?
Let's start with testing one model, in this case, your User model.
$ rails generate rspec:model user
1create spec/models/user_spec.rb
Great! Now lets write a simple test to see if we can save an instance of a User with a first_name
attribute. Navigate your user_spec.rb
located in spec/models/user_spec.rb
first things first, we want to require require "rails_helper"
at the top of every test file. (Doesn't feel very DRY to me, but whatever.)
Next, lets describe our first test for User. We want to check if a user can succesfully be saved with a first name.
1describe User do2 it "can have a first name" do3 user = User.new4 user.first_name = "Dwayne"5 user.save6 user.first_name.should == "Dwayne"7 end8end