Test Driven Development – writing better code

Test Driven Development is a development tool used to write code quickly and efficiently. The foundation of TDD lies in following three simple steps: (1) write a failing test, (2) write the simplest code to pass the test, (3) and then refactor. The goal is to tackle large projects by breaking them into smaller tasks and working on building the code base one step at a time.

This process works extremely well once you become practiced at it. And it’s power becomes quite apparent when tackling complex projects, such as an already existing web framework like Rails. Instead of worrying about how each of the components in an MVC framework will interact, you write a series of small tests and just get them to pass. As you continue to write tests, your failure messages will provide clues for where your code has holes and how you might be able to fix them.


Law of Demeter

The Law of Demeter, also known as the Principle of Least Knowledge, is a set of rules that is often implemented in test driven development. In summary, it proposes that any given object should ‘know’ as little as possible about the overall structure of code or any of the other components with which it interacts.

For example, in Rails, the models of any application are only responsible for interacting with the database and the controller. In order to affect the views, the model must pass information through the controller. This sort of ‘middle man’ interaction is a huge advantage when you need to fix only a section of code.

By breaking up a large application into smaller interacting bits, you can easily understand how the objects interact. Therefore, when you inevitably cause changes in the program’s behavior by re-writing code, it’s easy to identify what made those changes occur. When things break, it should be easier to fix since objects are less inter-dependent to function properly.


Tools for testing

If you’re getting into Ruby and Rails, it’s highly likely that you’ll use rspec and capybara at some point during your career. Rspec is a tool that allows you to write expectations for how Ruby should function and capybara provides a way to test real world scenarios for web applications. Once you get familiar with these tools, they can be incredibly useful for writing clean, maintainable code.

Here is a real example of some code written in rspec to create a CashRegister class. Some of the code has been indented to fit better on a normal desktop screen. Note that rspec is configured in a way to make it easy to understand what we expect to code to accomplish. The keyword subject is a shortcut for an instance of the CashRegister class (subject = CashRegister.new). So in the first test block, we are describing a method called total that ‘should print a starting total of $0.00’ and then modify the total anytime the purchase or pay methods have been called.

describe CashRegister do
  describe '#total' do
    it 'should print a starting total of $0.00' do
      expect(subject.total).to eq('$0.00')
    end

    it 'should print the correct total 
        after a payment or purchase' do
      subject.purchase(4.12)
      expect(subject.total).to eq('$4.12')
      subject.pay(3)
      expect(subject.total).to eq('$1.12')
    end
  end

  describe '#purchase(amount)' do
    it 'should add a specified amount to the total' do
      subject.purchase(4.12)
      expect(subject.total).to eq('$4.12')
    end
  end

  describe '#pay(amount)' do
    before(:each) do
      subject.purchase(2.18)
    end

    context 'when the payment is less than the total owed' do
      it 'should subtract a specified amount from the total' do
        subject.pay(2)
        expect(subject.total).to eq('$0.18')
      end
      it 'should return a string that shows the remaining total' do
        expect(subject.pay(2)).to eq('You still owe $0.18.')
      end
    end

    context 'when the payment is equal to the total owed' do
      it 'should reset the total to zero' do
        subject.pay(2.18)
        expect(subject.total).to eq('$0.00')
      end
      it 'should return a string that thanks 
          you for paying the exact total' do
        expect(subject.pay(2.18)).to 
            eq('Thank you for paying the exact amount. 
                There is no change.')
      end
    end

    context 'when the payment is greater than the total owed' do
      it 'should reset the total to zero' do
        subject.pay(3)
        expect(subject.total).to eq('$0.00')
      end
      it 'should return a string that shows your change' do
        expect(subject.pay(3)).to eq('Your change is $0.82.')
      end
    end
  end
end

Feel free to take this rspec file and write some code to get all of your tests to pass. Remember, you’ll need to install the rspec gem and make sure you have all of the files set up properly. Specifically, your rspec file should use require_relative to point to the actual code you are testing. Once you’ve got everything working, try to write the test from scratch to get some practice writing tests yourself. Remember, the goal is to (1) write one test, (2) make it pass, (3) refactor and then REPEAT. Don’t try to recreate the entire test file all in one go. Good luck!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s