Aristotle: Quality is not an act, it is a habit | pt.1

Mahati Meeru Nilaya
5 min readNov 26, 2016

--

TDD, Frameworks, and doing it right!

Testing is an essential part of the software development process. Test Driven Development is pretty much ubiquitous in the community and considered a healthy part of the development process.

But before one can speak in-depth about various test frameworks, what they do, and how they work, there are some big vocabulary terms to get familiar with.

Test Driven Development (Commonly referred to as TDD) : The idea that tests that check for behavior; particularly tests written to fail if certain conditions and behaviors are not met by the code, are written before the product code is written.

Think of a mediocre composer writing a score and playing back music she writes, checking key and pitch every couple bars before writing a new line. It is much much harder to write four sheets of music, find that 70% of it is off key and grating, and then try to fix it- than going line by line. Additionally, its very likely that the bars as they are fixed are less likely to fit with the theme and tones of greater piece.

Test Driven Development enable a sort of development outline for projects, more discretely than the greater outlines provided by user-stories or a wireframe.

Specs (Short for Specifications) : This one is relatively obvious but its always good to clarify as this term is thrown around a lot. Specifications, or specs in most industries, are used to describe the details of a particular kind of machinery, object, building, or site. The specifications of ‘what’ often various based on industry or field. For example, in my life as an archaeologist ‘site-specs’ referred to cartographic and historic details of the field-site and not, say the specifications of a construction site.

In web development the term ‘spec’ comes from TDD ideology and refers to the specifications that are written (as tests or otherwise) to describe and delineate the behavior of what a piece of code does.

I have heard the term tests and specs used interchangeably. In some programming languages like Ruby, this slight difference in parlance doesn’t have a realized difference in meaning or function. However in some languages like Java, there is a distinct semantic difference between tests and specs. I will not go into the reasons for distinguishing tests from specs, they can be found elsewhere. But in a nutshell, tests tend to check the exact functional output of a piece of code, (much like a boolean test) whereas specs tend to check behavior.

Rspec- a Ruby Testing Library

Rspec is one of the more popular testing libraries used to test Ruby code. Rspec is simply ruby code with the addition of some specialized methods to assist in testing. Requiring the rspec library enables access to the distinct methods the library holds.

As this is an intro-level survey into testing frameworks, I won’t delve into how exactly this library runs and what is happening under the hood of these new methods. This can be found elsewhere and is far easier to understand after a good awareness of how rspec works.

Rspec tests behavior, and it does primarily by using a describe block. This is one of those special methods that we have access to with this library. Typically, inside this block the tests for distinct behavior, i.e. the behavior one is testing for or setting up the architecture for, are delineated using the it block. For example:

 describe Hash do
it 'should return an empty hash' do
hash.new.should == {}
end
end

The thing whose behavior we are testing is the Hash via the describe block. The behaviors themselves, as in, the distinct behaviors we are testing for are delineated by the it block.

Say I wanted my code to eventually create a Hash called ice_cream. In addition, I wanted ice_cream to have key values of waffle_cone, sugar_cone, and cake_cone. Next I wanted each of these key to point to a different flavor as their values. So in effect I would want my Hash to look like the following:

ice_cream = { waffe_cone : 'chocolate',
sugar_cone : 'vanilla',
cake_cone : 'mint-chocolate-chip'
}

How would this translate into an rspec test? Assume I am not in the room of someone else writing code to show them my idea and explain. I also want to write my tests in a way that the web developers can recreate my hash piece by piece and make sure each step is correct. The thing whose behavior we are testing is the Hash called ice_cream. If we break that down a little more we can say that ice_cream should BE a Hash. Therefore ice_cream is the thing we are describing

describe ice_cream do

What are the behaviors and attributes ice_cream should have? It should be

  • a Hash
describe ice_cream do
it "should be a hash" do
Hash.new.should == ice_cream
  • ice_cream needs to have at least three key’s
describe ice_cream do
it "should have three keys of 'waffe_cone', 'sugar_cone', 'cake_cone' " do
ice_cream == Hash.new({ :waffle_cone, :sugar_cone, :cake_cone})

I did not put in this test the values for the distinct keys. Say later down this hash was actually being used for a program that would later assist in inventory for an ice cream shop?

What if that shop had different flavors than I had imagined. Or more likely, that shop had a hundred flavors that could be served with the different type of cone. Wouldn’t that change the data structure of this hash?

It would make more sense then to have each of these keys pointing to values that were arrays of ice cream flavors. If I had written my test above to include both the keys and the values, then further down the line I would have had to rewrite my test completely. Additionally, developers later on would have followed my specs and then had to completely restructure their hash. Instead of I break down my tests to be written behavior by behavior (however small), I have longer lasting more flexible specs!

describe ice_cream do
it "should have value of 'chocolate' for :waffle_cone" do
ice_cream == Hash.new({ :waffle_cone : 'chocolate', :sugar_cone, :cake_cone})
it "should have value of 'vanilla' for :sugar_cone" do
ice_cream == Hash.new({ :waffle_cone : 'chocolate', :sugar_cone : 'vanilla' , :cake_cone})
it "should have value of 'mint-chocolate-chip' for :cake_cone" do
ice_cream == Hash.new({ :waffle_cone : 'chocolate', :sugar_cone : 'vanilla' , :cake_cone : 'mint-chocolate-chip' })

notice all the tests within the it block are nested under the describe block. This way the tests can evolve and change overtime and are neatly organized under the main thing they are testing the behavior for!

Running this spec file will output a list of descriptive statements and failing tests. Specifically all the statements we wrote after the it These should statements read like a list of instructions and/or ingredients for our Hash object. These failing test statements will guide a developer to build a hash to the specifications we described via our tests.

The first failing test would be:

describe ice_cream do
it "should be a hash" do
Hash.new.should == ice_cream

What does this mean? That a new hash set to the variable ice_cream should exist. As the developer reads through the tests and gets them to pass, ice_cream will come to look exactly as we described!

This is how rspec runs and is used to write tests and build specs!

--

--

Mahati Meeru Nilaya

An Archaeological Art Historian turned Web Developer seeking to creatively integrate art, design, and code!