Scroll down to the script below, click on any sentence (including terminal blocks!) to jump to that spot in the video!
If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!Login Subscribe
Inline matchers are easy! I love that! But you can't reuse them across multiple spec files - that's a bummer. Fortunately, phpspec is awesome and so - of course - it does have a way to create a matcher that can be used anywhere. And... what's even better is that there are a lot of great examples to learn from.
And here's one: go to https://github.com/karriereat/phpspec-matchers - I... probably butchered that username - sorry! Anyways, this library is cool: it's just a big collection of custom matchers! Well, technically it's a phpspec extension, which means it's a "plugin" for phpspec.
Unfortunately, this library does not work with the latest version of phpspec at this time. But... who cares!? It is still an awesome source of inspiration for writing your own custom matchers. Each of these classes represents one matcher.
Here's our next goal: our scientists are starting to grow dinosaurs for the park, but have reported a possible bug in the
Dinosaur class! No problem! When you have a bug, the best thing to do is write a test for it: to describe the correct behavior so we can make sure our class has that.
In this case, someone reported that, when a dinosaur is created with a length of 15, sometimes... it shrinks! We've talked to our scientists and they say that some shrinking is ok, but a dinosaur should definitely not shrink below a length of 12. Wow, it turns out that growing a dinosaur is complex!
Let's translate this expected behavior into a new example:
function it_should_not_shrink(). Set the length of the dinosaur to
15 - and notice that we do get auto-completion now that the
setLength() method exists.
$this->getlength()... but... hmm. In this pretend example, the dinosaur is allowed to shrink some but not below 12. To reflect that, let's say:
|... lines 1 - 9|
|class DinosaurSpec extends ObjectBehavior|
|... lines 12 - 49|
As you probably saw, that is not a real matcher. So, the tests should fail. Try them:
They... pass? Hmm... ah! A typo! And this proves that each example must start with
its_. Try phpspec again:
There is the failure we expected.
We know that we could create an inline matcher. But... I kinda want to be able to re-use this in other spec classes. To do that, we can create a matcher class. In the
spec/ directory, create a
Matcher directory and then a new class:
BeGreaterMatcher... though this class could live anywhere. The namespace should be
spec then the directory path. So
|... lines 1 - 2|
But, let's keep this class empty for now: I just want to make sure that phpspec can see our new matcher. How? Via its config! Open
phpspec.yml, add a
matchers: section and then, very simply, list your matcher:
|... lines 1 - 5|
That's it! It won't fully work yet of course... but let's see what happens. Run phpspec:
spec\Matcher\BeGreaterMatcherdoes not exist.
This is basically a "class not found" error. Copy the namespace. Yeah... that looks correct... I don't see any typos. So... what's the problem? Autoloading!
composer.json file. We configured composer to be able to autoload things from the
src/ directory, but we haven't configured it to be able to autoload things from the
spec/ directory. phpspec does not need any autoloading to be setup to find the spec files - it handles all of that itself. But if you want to put any other, non-spec, classes in this directory - like a matcher - then we do need to set up autoloading.
No problem: copy the
autoload section, paste and change it to
autoload-dev. Tell composer to expect the
spec\\ namespace to live in the
|... lines 2 - 11|
To make Composer rebuild its autoloader, run:
Cool! Try phpspec again:
Much better! It does see it, and now we get:
Custom matcher spec\Matcher\BeGreaterMatcher must implement... some Matcher interface.
Apparently all matcher classes need to implement this interface. That makes sense! Let's do that next - and finish this!
Hey Mariano G.
Probably not so basic :) However you could suggest it to phpspec library ;)
"Houston: no signs of life"
Start the conversation!
#shouldBeGreaterThan() is not a built-in matcher? Whyyyy? It's something basic.