Photo by Goran Ivos on Unsplash
TDD(Test Driven Development) is AWESOME. TDD a.k.a red-green-refactor is a software development approach where you first write your test (specification) for your program. The test must specify all the behavior that you expect from your component or class or program. Run the test and just DON’T PANIC. As the name suggests it’s RED which means lots of error.
Now in the second phase - GREEN phase, you turn all your reds (error) to greens (error-free code). You actually write behavior of your program in this step. REMEMBER that you cannot directly run your program, you need to validate your program behavior using Test only. So for each modification in your program, you run your test file. This ensures that you fulfill your test cases.
Now the final step -REFACTOR, where you manage your spaghetti code. This is an IMPORTANT phase where you get a chance to improve your codebase readability and maintainability. The motivation here is that your program requirements may change later, so if you don’t refactor then GOOD LUCK fixing your code LATER. Some companies also have implemented strict policies regarding this.
The main core advantages of TDD, I found to my knowledge and experience are:
You are adding tests, hence contributing directly to Quality of Software/Program.
You are somewhat providing documentation for your program.
You improve codebase.
You can easily automate the test process for faster development.
Your program could have affected other program so, this can be traced as quickly as possible.
You gradually overcome the error PHOBIA. You develop a habit of reading error messages.
USING TDD
Enough of TDD talks let’s implement it. (SPOILER ALERT: section below involves codes)
To demonstrate, I have used **Ruby Programming language. I will be using [Rspec ](rspec.info/)**to test my ruby program. If you are new to Ruby or RSpec, WORRY NOT you will find them very similar to English. For installation
Consider a Requirement
**Write a class for a Jukebox with attribute songs. Embed methods to play current song, next song, shuffle song, add songs.**
songs = [“song1.mp3”, “song2.mp3”,”song3.mp3”]
jukebox = Jukebox.new(songs)
jukebox.play
#=> “song1.mp3”
jukebox.next
#=> “song2.mp3”
jukebox.previous
#=> “song1.mp3”
jukebox.shuffle
#=> “song2.mp3”
jukebox.add_song(“songs4.mp3”)
#=> [“song1.mp3”, “song2.mp3”,”song3.mp3”, “song4.mp3”]
So Now let’s start with a test file which states all behavior of given requirements. Convention for naming test file for a rubyfile ruby_file
is ruby_file
+ _spec.rb
. So I have prepared spec
file for this program as
#juke_box_spec.rb
require '**juke_box**'
describe **JukeBox** do
let(:songs) {['song1.mp3','song2.mp3','song3.mp3']}
describe '**.play**' do
subject {JukeBox.new(songs).play}
it 'should return current song' do
expect(subject).to eq('song1.mp3')
end
end
describe '.next' do
subject {JukeBox.new(songs).next}
it 'should return next song' do
expect(subject).to eq('song2.mp3')
end
end
describe '.previous' do
subject {JukeBox.new(songs).previous}
it 'should return previous song' do
expect(subject).to eq('song3.mp3')
end
end
describe '.add_song' do
subject {JukeBox.new(songs).add_song(new_song)}
let(:new_song) {'song4.mp3'}
it 'should return new songs list' do
expect(subject).to match_array(songs.push(new_song))
end
end
describe '.shuffle' do
subject {JukeBox.new(songs).shuffle}
let(:previous_first_song){'song1.mp3'}
it 'should not return previous songs order list' do
expect(subject).not_to eq(previous_first_song)
end
end
end
Now we run this test file with the command rspec juke_box_spec.rb``.The first error message we get is the file
juke_box.rb not found so let’s create a file named
juke_box.rb, run test again we get an error message
NoMethodError``, so specify methods in your program. Again run the test you will get another error fix it and continue this process until you create your program file similar to mine. And also don’t forget to REFACTOR!
#juke_box.rb
class JukeBox
#define constructor
def initialize(songs_list)
#create instance variable songs and current_song
@songs=songs_list
@current_song=0
end
def play
#Last line is returned by default in ruby function
@songs[@current_song]
end
def next
@current_song=(@current_song+1)% @songs.length
play
end
def previous
@current_song<=0 ? @current_song=@songs.length-1 : @current_song-=1
play
end
def shuffle
@songs.shuffle!
#Optional to set current song to first song
@current_song=0
play
end
def add_song(new_song)
#Push new song to songs array
@songs << new_song
end
end