I took the ideas presented here and built a gem called Mustard. Check it out!
There are several expectation/assertion interfaces available for writing tests/specs. Here are some issues I have with them.
- The order of
assert_equals
feels backwards - Oh wait, that should be
assert_equal
(that too) - I like to write the subject first
- Adds 30+ methods to Object
- Any matchers you want to add are another method on Object
- Still too few matchers, so it's ugly:
foo.must_be :<, 10
- too.many.method.calls.to.simulate.english
- The space makes for some awkward syntaxes that cause warnings (when used with
==
,>
, etc.) eq()
and such aren't bad, but may need parenthesis- Pollutes the spec context with methods for each matcher
I haven't used the RSpec expect()
interface enough to know cons.
# should returns an object which can have matchers called on it
5.should.eq 5
5.should.equal 5
# should_not can be used to do a reverse match
5.should_not.equal 7
# some comparison matchers
5.should.be_less_than 8
5.should.be_greater_than 3
5.should.be_lt 8
5.should.be_gt 3
5.should.be_gte 5
true.should.be_true
false.should.be_false
# call the method and see if it is true
[].should.be :empty?
5.should.be :between?, 3, 7
# add matchers
Should.matcher :be_empty do # any args will be passed into block
empty? # runs in the context of the object and returns true/false
end
[].should.be_empty
[].should_not.be_empty # message: Expected [] to not be empty
# add matcher through class
Should.matcher :be_empty, BeEmptyMatcher
class BeEmptyMatcher
# methods in here for defining behavior and messages.
end
I like this because it does not pollute the Object space much (just should
and should_not
). Also every method called after it is simply a matcher. No crazy method chains.
What do you think? If there's enough interest I'll write this up as a plugin for both RSpec-Core and MiniTest.
Compare your proposed:
With raggi's (and what would be very similar in minitest) bacon:
(comments stripped on both)
Do you see the main difference there?
In bacon/minitest you only need to know ruby. You only need to know one object system. You only need to know one way to create behavior. Pretty much anyone can look at the code and simply understand what is going on.
In rspec and your example, you need to know 2: ruby and the testing system's notion of objects, classes, and methods. I have no idea what that
empty?
sitting in the middle of nowhere is supposed to do to anything. I'd bet that 90% of the ppl out there give hand-wavey explanations on how rspec and your proposal actually work.I will never wrap my head around why there is an entirely new class hierarchy, inheritance, and module system in rspec and your proposal. I will never wrap my head around why you want
Should.matcher name do
to be some obtuse alias fordef name
. Levels of indirection just make things more confusing, harder to debug and slower. But most importantly, it is much harder to teach to the people who need it most.