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.
If you feel that the language of minitest is lacking, you should say so. They get implemented as assertions anyhow and just glued into Object.
Well no, actually. If your argument is against global pollution, then anything > 0 is bad. You can't have it both ways. As pointed out elsewhere, I always scope my methods on object to must_* and wont_* so it really isn't any worse than your should/should_not.
What IS worse is the extra method calls and levels of indirection.
Also, as I've pointed out, you can disable the expectation methods in minispec. Clearly 0 methods infecting Object is better than your 2. Right? I mean... I do get to use your own logic against you, right?
I only make two expectations when it make sense to have both. This is the whole:
thing.
must_not_be_empty
is just as useless so why provide it? Your need for consistency actually encourages bad testing and a false sense of security.Finally (sorry)... I walked through bacon's method flow in my "Size isn't Everything" talk at cascadia ruby conf last year with a nice illustration and everything. You might want to check it out. It is a very beautiful little framework.