Getting started
A first specification: see it fail, make it pass, run it with the fix command.
This page builds a small project, greeting, with a class in lib/greeting.rb and its specification in fix/greeting_fix.rb.
Install
gem install fix-command
fix-command brings fix with it: the fix gem holds the language of specifications, and fix-command the fix command, which runs them. In a project with a Gemfile, add gem "fix-command" to it instead, run bundle install, and run the commands of this guide through bundle exec.
A specification
Specifications live in the fix directory of a project, usually one per file, in files whose names end with _fix.rb. In fix/greeting_fix.rb:
require "fix"
require_relative "../lib/greeting"
Fix :Greeting do
on :call, "Alice" do
it MUST eq "Hello, Alice!"
end
end
exit(Fix[:Greeting].test { Greeting.new })
require "fix"loads Fix.require_relative "../lib/greeting"loads the class: the test at the end needs it, the specification does not.Fix :Greeting do … endbuilds a specification and registers it under the nameGreeting. Its block is read once, when the file is loaded.on :call, "Alice"opens a context: the method sent to the subject,call, with its argument.it MUST eq "Hello, Alice!"is an expectation about what comes back: a level of requirement,MUST, and a matcher,eq.- The last line tests a subject against the specification. Its block, the subject block, builds the subject, a new one for each expectation;
testwrites one line per expectation and returns whether all of them are met;exitmakes that the status of the process.
The specification names no class: it says what a greeting does, and the test, on the last line, picks what to test. The same specification could test another class tomorrow.
The code
A first version of the class, in lib/greeting.rb:
class Greeting
def call(name) = "Hello #{name}!"
end
A first run
A specification file is a Ruby program: run it with ruby, from the root of the project, so that the lines name the file from there.
ruby fix/greeting_fix.rb fix/greeting_fix.rb:6: Failure: expected "Hello Alice!" to eq "Hello, Alice!"
One line per expectation: where it is, the file and the line of its it; its outcome, Failure; and what happened, expected ACTUAL to eq EXPECTED. A comma is missing. The status of the process is 1, as for any failing program, which is all a terminal, a Rakefile or a CI service needs to know.
Making it pass
With the comma, in lib/greeting.rb:
class Greeting
def call(name) = "Hello, #{name}!"
end
This time, run the fix command, from the root of the project:
fix fix/greeting_fix.rb:6: Success: expected "Hello, Alice!" to eq "Hello, Alice!" 1 file met
The expectation is met. fix runs each _fix.rb file of the fix directory in a process of its own, lets its lines through, and ends with how many files were met; its status is 0 when all of them are. With one file, it says what ruby said; with fifty, it is the command to run.
That is the whole cycle: a specification says what a subject must do, a test picks the subject, and the status tells whether it does. The next page writes richer specifications: several contexts, parameters, and the two other levels, SHOULD and MAY.