Rex
Rex is the spec framework built into Metorex. A suite written for RSpec runs under metorex spec with no gems installed. RSpec names Rex, and require "rspec", require "rspec/core", and the other RSpec paths load it.
Running a Suite#
metorex spec runs the files under spec/ whose names end in _spec.rb, as rspec does. It reads .rspec, .rspec-local, and SPEC_OPTS, loads spec/spec_helper.rb when there is one, and takes RSpec's options, which metorex spec --help lists.
metorex spec
metorex spec spec/ledger_spec.rb:14
metorex spec --format documentation --seed 1234
A script run with metorex that names RSpec loads Rex the first time it does, and runs the examples it defined as it ends, as require "rspec/autorun" does.
A Suite and Its Output#
lib/ledger.rb:
class Ledger
def initialize
@entries = []
end
def record(amount)
if amount.zero?
raise ArgumentError, "an entry needs an amount"
end
@entries << amount
self
end
def balance = @entries.sum
def overdrawn? = balance.negative?
end
spec/ledger_spec.rb:
require_relative "../lib/ledger"
RSpec.describe Ledger do
subject(:ledger) { Ledger.new }
it "starts at zero" do
expect(ledger.balance).to eq(0)
end
context "with two entries" do
before { ledger.record(120).record(-45) }
it "sums them" do
expect(ledger.balance).to eq(75)
end
it "is not overdrawn" do
expect(ledger).not_to be_overdrawn
end
end
it "refuses an entry of zero" do
expect { ledger.record(0) }.to raise_error(
ArgumentError, "an entry needs an amount"
)
end
it "rounds a balance" do
ledger.record(10).record(-3)
expect(ledger.balance).to eq(6)
end
end
metorex spec --format documentation prints the same as rspec --format documentation does for this suite, apart from the times:
Ledger
starts at zero
refuses an entry of zero
rounds a balance (FAILED - 1)
with two entries
sums them
is not overdrawn
Failures:
1) Ledger rounds a balance
Failure/Error: expect(ledger.balance).to eq(6)
expected: 6
got: 7
(compared using ==)
# ./spec/ledger_spec.rb:30:in 'block (2 levels) in <top (required)>'
Finished in 0.01056 seconds (files took 0.07906 seconds to load)
5 examples, 1 failure
Failed examples:
rspec ./spec/ledger_spec.rb:28 # Ledger rounds a balance
Options of Its Own#
Rex adds these to RSpec's options:
--jobs Nruns the top-level groups in N worker processes, and--jobs autoruns one per processor. The output reads as it does with one job, since the groups' results are reported in the order a serial run would report them.--verify-parallelruns the suite again in one process with the same seed after a parallel run, and warns about each example whose outcome changed, which points at state shared between groups.--coveragereports the lines and branches of the loaded files that ran, counted by the interpreter rather than by a gem.--coverage-formatpickssummary,lcov, orjson,--coverage-dirsays where the files go,--coverage-threshold PERCENTfails a run below it, and--coverage-exclude PATTERNleaves files out.--no-fast-pathsruns the Ruby versions of the parts of Rex that also have native versions, so a difference between the two can be checked.--no-diffleaves out the diff a failure comparing two values prints.
metorex spec --coverage on the suite above ends with:
Coverage: 100.00% of lines (10 of 10) and 100.00% of branches (2 of 2) in 1 file
lib/ledger.rb 100.00% of lines 100.00% of branches
RSpec's Own Suites#
The RSpec libraries' own suites run under metorex spec and under MRI's own rspec, one spec file to a process:
| Suite | Passing under MRI | Passing under Metorex | Examples |
|---|---|---|---|
| rspec-core | 2239 | 2238 | 2258 |
| rspec-expectations | 2438 | 2438 | 2455 |
| rspec-mocks | 1794 | 1794 | 1806 |