Fixrb

Fix guide, version 1

Composing specifications

A specification is a matcher: one may require another, here and in other test frameworks.

A specification says what a subject does. Some of that is said once and holds for many subjects: what an empty collection does, what a name looks like, what any plugin answers. Written as a specification of its own, it is required by the others.

In a specification: fix

The matcher fix(:Name) is met when the actual value meets the specification of that name. Here a stack must be empty when it is new, and must not be once something is pushed:

require "fix"

Fix :Empty do
  on :empty? do
    it MUST be_true
  end

  on :size do
    it MUST eq 0
  end
end

Fix :Stack do
  it MUST fix(:Empty)

  on :push, 1 do
    it MUST_NOT fix(:Empty)

    on :last do
      it MUST eq 1
    end
  end
end

exit(Fix[:Stack].test { [] })
ruby stack_fix.rb
stack_fix.rb:14: Success: expected [] to fix Empty
stack_fix.rb:17: Success: expected [1] not to fix Empty
stack_fix.rb:20: Success: expected 1 to eq 1

In Ruby: match?

A specification answers match?, as any matcher does. Its block gives the value, and the answer says whether the value meets the specification. Here Empty holds for an array, a hash and a string alike:

require "fix"

Fix :Empty do
  on :empty? do
    it MUST be_true
  end

  on :size do
    it MUST eq 0
  end
end

Fix[:Empty].match? { [] }    # => true
Fix[:Empty].match? { {} }    # => true
Fix[:Empty].match? { "" }    # => true
Fix[:Empty].match? { [nil] } # => false

match? writes nothing: test is there for the lines, and run for the results.

In other frameworks: matchi-fix

The matchers of Matchi work in any test framework, and matchi-fix makes a specification of Fix one of them: Matchi::Fix.new(:Name), or Matchi::Fix.new { … } for one written in place. Install it, gem install matchi-fix, and require matchi/fix:

require "fix"
require "matchi/fix"

Fix :Empty do
  on :empty? do
    it MUST be_true
  end
end

matcher = Matchi::Fix.new(:Empty)
matcher.to_s          # => "fix Empty"
matcher.match? { [] } # => true

Spectus.must(matcher).call { [nil] }.to_s # => "Failure: expected [nil] to fix Empty"

The last line uses Spectus, which Fix is built on. In minitest, assert takes its answer: assert Matchi::Fix.new(:Empty).match? { [] }. A project that has its tests in another framework can use the same specifications in those tests, without moving them.

In a specification of Fix, it MUST Matchi::Fix.new(:Empty) and it MUST fix(:Empty) are the same: fix needs no other gem.