Shoulda use this in Pharo
Phexample is the new black in unit testing for Smalltalk. It extends SUnit with two features: test dependencies, and RSpec-like expectation matchers. Test dependencies are covered on Niko’s blog, who’s developing Phexample with me, as well as on the JExample website. I shall thus focus on expectation matchers here.
Expectation matchers let you set expectations on your object. Expectations are also useful if you just use plain old SUnit test cases. They throw the same test failure as SUnit’s assertion, but are more readable in the source code as well as throw more readable failures messages.
Let’s start with an example.
Get yourself the latest Pharo image and
Gofer it
squeaksource: 'phexample';
addPackage: 'Phexample;
load
then open a workspace and evaluate
stack := Stack new.
stack size should = 0.
this creates a new stack and asserts that its size should be zero. For the sake of the example, let’s evaluate a failing expectation
stack push: 42.
stack top should = 4711.
which raises TestFailure: expected 4711 but got 42 (using =).
There are expectation matchers for all basic comparisons: greater than, less than, et cetera. If you need to negate a comparison just write
stack top should not = 4711.
There are special matchers to set expectations on boolean return values.
stack isEmpty should be true.
alternatively you can write
stack should be isEmpty.
which often reads like LOLCAT SPEAK, but works quite nice with selectors that do not include a verb such as
42 should be even.
Note: matching of boolean expectations is an open issue. We would love to allow you to write stack should be empty, which is not only be more readable but would also allow us to provide better failure messages since we know that you wanted to test isEmpty. However, we fear that breaking Pharo’s senders-of feature as well as rename and other refactorings might not be worth the added value in reabability.
We welcome your feedback on this issue. For example, Oscar suggested to use
stack isEmpty wouldyaknow
however, we are not sure how serious this suggestion is to be taken :)
Back on topic.
If you expect some code to raise an error, just write
stack := Stack new.
[ stack pop ] should signal: Error
and to check the error message
[ stack pop ] should signal: Error withMessageText: 'this stack is empty'.
or even
[ stack pop ] should signal: Error withMessageText: [ :m |
m should beKindOf: String.
m isEmpty should not be true.
m should endWith: 'is empty' ]
which leads us to more matchers, such as
stack should beKindOf: Collection.
which sets an expectation on the type of an object.
Note: it seems sensible to add more expectations that match the dynamic type of objects, such as duck typing and responds-to. We plan on doing this, please let us know if you have a specific use case.
string should startWith: prefix.
string should endWith: prefix.
string should matchRegex: regexString.
are some expectations that you can set on strings.
Certainly there are more common expectations on basic types such as strings and collections. Again, please let us know if you have a specific use case. One of the things we want to do with Phexample is to be driven by user needs rather than planning upfront which features you might need (and nevertheless always guessing wrong…)
A last one, suggest by Lukas. If you expect some code to run within a given duration, just write
[ ... ] should runWithin: 20 milliSeconds.
which aborts with a failure if the given code takes longer than 20 milliseconds to run.
You can find the full list of expectation matchers in the expecting protocols of the PhexMatcher class. All matchers are well covered with tests, thus for plenty examples of their use just refer to the ForExampleMatcher class (which, of course, sublcasses the Phexample class, thus all its test methods start with should..).
PS: current versions of Omnibrowser do not display a test icon for Phexample test methods. This bug has been reported and a fix provided and will thus soon be fixed in your Pharo.
November 21st, 2009 at 22:59
Pingback! I commited some code that should let you write
Stack isEmpty should be true.
November 21st, 2009 at 22:59
And I wrote a small blog entry about it: http://smalltalkthoughts.blogspot.com/2009/11/and-its-done-phexample-has-no-more.html
November 22nd, 2009 at 13:21
Take a look at Mocketry (http://www.squeaksource.com/Mocketry/ or http://www.cincomsmalltalk.com/publicRepository/Mocketry(Bundle).html)
November 22nd, 2009 at 17:10
Thanks, Dennis!
Mocketry is based on SSpec by Dave Astels (it does even come with nice documentation). We weren’t aware of that when we wrote Phexample. I guess, copying RSpec’s expectations matcher DSL was a too obvious thing to do :) Are you an active user of Mocketry and SSpec, what is your experience with it?
November 25th, 2009 at 09:09
[...] initial design of Phexample, boolean expectation matchers had a somewhat awkward syntax, which got soon nicknamed “lolcat syntax” by [...]
January 8th, 2010 at 18:41
The documentation for SSpec is offline by now.
January 8th, 2010 at 23:24
Wow, that was quick surrender.