matchi
Framework-agnostic matchers for Ruby.
A matcher is built with an expected value, then asked whether an actual value matches. It answers true or false, and leaves negation, messages and reports to your test framework.
- Version
- 5.0.0
- Ruby
- 3.3 or later
- Dependencies
- None
- License
- MIT
- Used by
- Fix 1.0
Install
Add gem "matchi" to your Gemfile, or run gem install matchi.
Usage
The block given to match? yields the actual value once, and to_s completes the sentence “expected … to …”.
require "matchi"
matcher = Matchi::Eq.new(42)
matcher.match? { 42 } # => true
matcher.match? { 41 } # => false
matcher.to_s # => "eq 42"
Matchers
Be- Identity, with
equal?. Eq- Equivalence, with
eql?, between values of the same class. BeAKindOf- A kind of a module, given directly or by name.
BeAnInstanceOf- An instance of a class, given directly or by name.
BeWithin- An
Integer,Float,RationalorBigDecimalwithin a delta of the expected number. Match- A string or a symbol that matches a
Regexp. Satisfy- A value for which a block answers
true. Predicate- A value whose predicate answers
true::be_emptycallsempty?. RaiseException- A block that raises an exception of a given class, optionally with a given message.
Change- A block that changes what a public method returns, optionally
by,by_at_least,by_at_most,to, orfromandto.
The expected value decides
When a matcher compares the expected value with the actual value, the expected value receives the call: Matchi::Eq.new(a) evaluates a.eql?(b), never b.eql?(a). An actual value that lies about its own equality cannot pass:
require "matchi"
actual = "bar"
def actual.eql?(*)
true
end
actual.eql?("foo") # => true
matcher = Matchi::Eq.new("foo")
matcher.match? { actual } # => false
Three cases rely on values produced by the object under test, and so on its honesty: Predicate calls one of its methods, the by refinements of Change compare and subtract the values it returns, and the message filter of RaiseException reads the message of the exception raised. The README says which matchers give which guarantee.
The reasons for this rule are in The Fundamental Distinction Between Expected and Actual Values in Testing.
With your test framework
Any framework can use a matcher in a few lines. With Minitest:
require "matchi"
require "minitest/autorun"
class TestAnswer < Minitest::Test
def assert_matches(matcher, actual)
message = "expected #{actual.inspect} to #{matcher}"
assert matcher.match? { actual }, message
end
def test_answer
assert_matches Matchi::BeAKindOf.new(Integer), 42
assert_matches Matchi::BeWithin.new(0.01).of(0.3), 0.1 + 0.2
end
end
Documentation
- README: every matcher with its arguments and errors, and the differences from RSpec.
- API reference
- RubyGems
- Source code