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
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!