- a *nix system
- Ruby installed -
rvm
(curl -sSL https://get.rvm.io | bash
) is useful for installing the latest version and keeping gems local to your user - a directory called
workspace
in your home directory - Atom editor installed - https://atom.io/
cd ~/workspace/
(go to your workspace)mkdir fizzbuzz
(make a new directory)cd fizzbuzz
(change into it)gem install bundler
(install a gem (1) called 'bundler')bundle init
(run Bundler (2) program, passing theinit
argument - this creates a file calledGemfile
)atom Gemfile
(open the file in Atom)- Change
gem "rails"
togem "rspec"
and go back to the command line (this tells Bundler that we want to install a gem called RSpec) bundle install
(run Bundler again, this time passing it theinstall
argument)bundle exec rspec --init
(tell the bundler program to run the rspec program, passing the--init
argument to it)mkdir lib
(make another directory to hold the actual code)touch lib/fizzbuzz.rb
(create a file that we'll use later)atom spec/fizzbuzz_spec.rb
(open a file to hold our tests - thespec
directory was created byrspec --init
)
In the file you've just opened, require the fizzbuzz file and start a description for it:
require 'fizzbuzz'
describe FizzBuzz do
end
We are describing something with the name FizzBuzz
so that clearly needs to exist.
Open lib/fizzbuzz.rb
in Atom e.g. run atom lib/fizzbuzz.rb
on the command line and then create the FizzBuzz
module:
module FizzBuzz
end
Aside: by putting the fizzbuzz.rb
file into the lib
directory, RSpec can find it so we can include it simply with require 'fizzbuzz'
, rather than having to tell the test file where it is on the file-system with a relative or absolute path e.g. require '../fizzbuzz.rb'
or require '/Users/billbums/workspace/fizzbuzz/fizzbuzz.rb'
.
At this point we can run RSpec and see the output:
bundle exec rspec
You should see something which looks like this:
No examples found.
Finished in 0.00029 seconds (files took 0.07641 seconds to load)
0 examples, 0 failures
So everything runs, we just haven't written any tests yet.
Next, let's write a test. If it's not already, open up the fizzbuzz_spec.rb
file in the spec
directory: atom spec/fizzbuzz_spec.rb
and add a test to it. We'll test the basic case when we pass 1
to a function called fizzbuzz
and the test will look like this:
it "returns 1 for 1" do
expect(FizzBuzz.fizzbuzz(1)).to eq(1)
end
It needs to go inside the describe
block, so the whole thing will look like this:
describe FizzBuzz do
it "returns 1 for 1" do
expect(FizzBuzz.fizzbuzz(1)).to eq(1)
end
end
OK, so what have we written? Well, we've called the fizzbuzz
method on the FizzBuzz
module and passed 1
into it: FizzBuzz.fizzbuzz(1)
.
We've passed that whole thing into a method called expect
: expect(FizzBuzz.fizzbuzz(1))
Then we've called to
on whatever that returns: expect(FizzBuzz.fizzbuzz(1)).to
And then, finally, we've said that we want that to be equal to 1
by using the eq
method: eq(1)
(Notice that we have left the brackets off the to
method to make this read more like a sentence, which is a convention that's often used).
We can run the tests again, now that one exists.
Run with: bundle exec rspec
The output should look something like this:
F
Failures:
1) FizzBuzz returns 1 when passed 1
Failure/Error: expect(FizzBuzz.fizzbuzz(1)).to eq(1)
NoMethodError:
undefined method `fizzbuzz' for FizzBuzz:Module
# ./spec/fizzbuzz_spec.rb:5:in `block (2 levels) in <top (required)>'
Finished in 0.00179 seconds (files took 0.09138 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/fizzbuzz_spec.rb:4 # FizzBuzz returns 1 when passed 1
The test has failed because the method we're calling doesn't exist. That's fine - we'd like to see the test fail first before we make it pass.
Test Driven Development (TDD) is a software development practice which involves writing a test first, before the code to make it pass actually exists.
You write the test first, run it to see it fail, write the code to make it pass then run the test again and see that all is well (ideal world).
This has several benefits:
- you know that what you've written definitely satisfies your test
- you can write just enough code to make the tests pass leading to less complexity and full test coverage
- your code has tests (it's much harder to go back and write them retrospectively)
Finally (for this introduction) we can make this test pass.
Adding this simple method inside the FizzBuzz
module will make our first test pass (we have to add more tests for the rest of FizzBuzz):
def self.fizzbuzz(n)
n
end
Run the tests again, as before, and see your triumph.
Ruby code can be wrapped up into a package so that it can be installed and used in other programs, projects and by other people. These packages of code are called 'Gems'. Reusing code that other people have written is essential if you want to get anything done... See https://www.ruby-lang.org/en/libraries/ We've installed, via a Gem, a program called Bundler. We can give Bundler a list of Gems (in the `Gemfile`) that we want to install and it will manage the installation of all of them. (Imagine you had to install 10 different Gems - running 'gem install ...' 10 times would be tedious and error-prone).Bundler will also make sure that your program can find the Gems to be able to use, plus allow you to run programs installed via Gems e.g. the rspec
program.
Bundler also generates a file called Gemfile.lock
, which you should checkin to source control (Git). It contains the specific versions of the dependencies which were installed, so if you install RSpec version 1.2.3 and everything works then the next person to follow your instructions should get the same version to avoid any unforseen problems.
The Bundler site is here: http://bundler.io/