October 11, 2013

Ruby FizzBuzz kata with TDD

Yesterday I wanted to code something just for fun. So I've decided to do FizzBuzz kata. It was pretty easy and fun.

Today I've discovered that it is popular programming excercise, so I've deciced to share my solution.

I have followed TDD. So I've started with tests. Here you can find complete set of tests, but it is important to note that you should write just one test at the time, implemented minimal code to make it pass and then write another test and so and so...

If you are new to TDD feel free to use my tests (one by one) and implement needed code to make it pass. At the end you should have code which pass all the tests.

So here is my solution.

Tests:

# spec/fizz_buzz_spec.rb

require 'fizz_buzz'
require 'stringio'

describe FizzBuzz do
  describe '#fizz?' do
    it 'returns true if number is multiply of three' do
      expect(fizz_buzz.fizz?(9)).to be true
    end

    it 'returns false if number is not multiply of three' do
      expect(fizz_buzz.fizz?(1)).to be false
    end
  end

  describe '#buzz?' do
    it 'returns true if number is multiply of five' do
      expect(fizz_buzz.buzz?(10)).to be true
    end

    it 'returns false if number is not multiply of five' do
      expect(fizz_buzz.buzz?(1)).to be false 
    end
  end

  describe 'print_number' do
    it 'prints Fizz if number is multiply of three' do
      output = capture_stdout { fizz_buzz.print_number(6) }
      expect(output).to eq "Fizz\n"
    end

    it 'prints Buzz if number is multiply of five' do
      output = capture_stdout { fizz_buzz.print_number(10) }
      expect(output).to eq "Buzz\n"
    end

    it 'prints FizzBuzz if number is multiply of three and also multiply of five' do
      output = capture_stdout { fizz_buzz.print_number(15) }
      expect(output).to eq "FizzBuzz\n"
    end

    it 'prints given number if it is not Fizz nor Buzz' do
      output = capture_stdout { fizz_buzz.print_number(2) }
      expect(output).to eq "2\n"
    end
  end

  describe '#run' do
    it 'prints succession of numbers starting with one and replacing fizz and buzz numbers' do
      output = capture_stdout { fizz_buzz.run }
      expect(output.lines.first(5).join).to eq "1\n2\nFizz\n4\nBuzz\n"
    end
  end

  def fizz_buzz
    FizzBuzz.new
  end
end

def capture_stdout &block
  old_stdout = $stdout
  fake_stdout = StringIO.new
  $stdout = fake_stdout
  block.call
  fake_stdout.string
ensure
  $stdout = old_stdout
end

Code:

# lib/fizz_buzz.rb

class FizzBuzz
  def run
    100.times do |n|
      print_number n+1
    end
  end

  def fizz?(number)
    number % 3 == 0
  end

  def buzz?(number)
    number % 5 == 0
  end

  def print_number(number)
    if fizz?(number)
      print "Fizz"
    end
    if buzz?(number)
      print "Buzz"
    end
    if !buzz?(number) && !fizz?(number)
      print number
    end
    puts
  end
end

And finally the script which will run it all.

#!/usr/bin/env ruby

require_relative '../lib/fizz_buzz'

FizzBuzz.new.run

It is probably not the best solution but it is working and has 100% test coverage!

Hey there!

My name is Patrik Bóna and I am the only programmer at Memberful. This blog is kind of dead, but I just started my own Ruby on Rails screencast. Follow me on Twitter if you want to be notified about my newest videos.