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.
I mentioned this on Twitter this morning but thought I would be worth putting my thoughts here too (and over more than 140 chars).
I played around with similar earlier this year in https://github.com/gshutler/mustard. I never published it but it seems I had similar thoughts.
Things that motivated me:
Lack of pollution
Mustard extends
Object
withmust
andmust_not
, everything else hangs off theMustard
proxy.Intuitive
RSpec and similar matchers have often tripped me up as I couldn't remember which way around spaces and statements needed to be, when parantheses became mandatory, how the
be_
statement was written, etc.Mustard works with regular boolean expressions which you would use with Ruby so there's no new syntax to learn. If your regular boolean statement is
foo.vaguely_sensible? :bar
thenfoo.must.vaguely_sensible? :bar
is a working assertion.Readability != "Is English"
We're developers, we read code for a living. I know that
<=
means less than or equal to so why no just use that rather than added another set of vocabulary to learn/forget?More assertive verb
Referencing RFC 2119 SHOULD has weak connotations whereas MUST is assertive. Given that tests fail when your expectations aren't met
must
seems a better fit.All that being said I was doing it more as a thought experiment rather than a serious effort to create an alternative and I've continued to use RSpec matchers day-to-day. However, if there would be wider interest in refining this (I stopped at the point where there were diminishing returns between effort and interest) I'd be happy to pick it up again.