Migration from v1
[Updated] Patchwork Version
Patchwork has been updated to version 2. This new version allows to redefine PHP core functions and not only custom defined functions. (There are limitations, see http://patchwork2.org/limitations/).
This new Patchwork version seems to also fix an annoying issue with undesired Patchwork cache.
[Changed] Setup Functions - BREAKING!
On version 1 of Brain Monkey there where 4 static methods dedicated to setup:
Brain\Monkey::setUp()
-> before each test that use only functions redefinition (no WP features)Brain\Monkey::tearDown()
-> after each test that use only functions redefinition (no WP features)Brain\Monkey::setUpWp()
-> before each test that use functions redefinition and WP featuresBrain\Monkey::tearDownWp()
-> after each test that use functions redefinition and WP features
This has been simplified, in fact, only two setup functions exists in Brain Monkey v2:
Brain\Monkey\setUp()
-> before each test that use functions redefinition and WP featuresBrain\Monkey\tearDown()
-> after each test, no matter if for functions redefinition or for alsoWP features
Which means that for function redefinitions, only Brain\Monkey\tearDown()
have to be called after each test, and nothing before each test.
To also use WP features, Brain\Monkey\setUp()
have also to called before each test.
[Changed] New API - BREAKING!
Big part of Brain Monkey is acting as a "bridge" between Mockery an Patchwork, that is, make Mockery DSL for expectations available for functions and WordPress hooks.
To access the Mockery API, Brain Monkey v1 provided two different methods:
using static methods on the
Brain\Monkey
classusing static methods on one of the three feature-specific classes
Brain\Monkey\Functions
,Brain\Monkey\WP\Actions
orBrain\Monkey\WP\Filters
For example:
In Brain Monkey v2 there's only one method, that makes use of functions:
Renamed method for done actions
For WordPress filters, there were in Brain Monkey v1 two methods:
Filters::expectAdded()
Filters::expectApplied()
named after the WordPress functions add_filter()
/ apply_filters()
But for actions there were:
Actions::expectAdded()
Actions::expectFired()
expectAdded()
pairs with add_action()
, but expectFired()
does not really pair with do_action()
: this is why in Brain Monkey v2 the method expectFired()
has been replaced by the function expectDone()
.
So, in version 2 there are total of 5 entry-point functions to Mockery API:
Brain\Monkey\Functions\expect()
Brain\Monkey\Actions\expectAdded()
Brain\Monkey\Actions\expectDone()
Brain\Monkey\Filters\expectAdded()
Brain\Monkey\Filters\expectApplied()
[Changed] Default Expectations Behavior - BREAKING!
In Brain Monkey v1, expectation on the "times" an expected event happen was required.
This test passed in Brain Monkey v1, because even if Actions::expectAdded()
was used, the test does not fail unless something like Actions::expectAdded('init')->once()
was used, which made the test pass only if add_action( 'init' )
was called once.
The reason is that Mockery default behavior is to add a ->zeroOrMoreTimes()
as expectation on number of times a method is called, so when the expectation is called zero times, that's a valid outcome.
This was somehow confusing (because reading expectAdded
one could expect the test to fail if that thing did not happened), and also made tests unnecessarily verbose.
Brain Monkey v2, set Mockery expectation default to ->atLeast()->once()
so, for example, the test above fails in Brain Monkey v2 if MyClass::doSomething()
does not call add_action('init')
at least once.
[Changed] Closure String Representation - BREAKING!
Brain Monkey allows to do some basic tests using has_action()
/ has_filter()
, functions, to test if some portion of code have added some hooks.
A "special" syntax, was already added in Brain Monkey v1 to permit the checking for hooks added using object instances as part of the hook callback, without having any reference to those objects.
For example, assuming a function like:
could be tested with in Brain Monkey v1 with:
The syntax for string representation of callbacks including objects is unchanged in Brain Monkey v2, however, the syntax for closures string representation has been changed to allow more fine grained control.
In fact, in Brain Monkey v1 all the closures were represented as the string "function()"
, in Brain Monkey v2 closure string representations also contain the parameters used in the closure signature:
The closure string representation does take into account:
name of the parameters
parameters type hints (works with PHP 7+ scalar type hints)
variadic arguments
static
closures VS normal closures
does not take into account:
PHP 7 return type declaration
parameters defaults
content of the closure
For example:
Note how type-hints using classes always have fully qualified names in string representation.
[Changed] Relaxed callable
check
callable
checkIn Brain Monkey v1 methods and functions that accept a callable
like, for example, second argument to add_action()
/ add_filter()
, checked the received argument to be an actual callable PHP entity, using is_callable
:
For these reasons, it was often required to create a mock for unavailable classes or functions just to don't make Brain Monkey throw an exception, even if the mock was not used and not relevant for the test.
Brain Monkey v2 is less strict on checking for callable
and it accepts anything that looks like a callable.
Something like [SomeClass::class, 'aMethod']
would be accepted even if SomeClass
is not loaded at all, because it looks like a callable. Same goes for 'Some\Name\Space\aFunction'
.
However, something like [SomeClass::class, 'a-Method']
or [SomeClass::class, 'aMethod', 1]
or even Some\Name\Space\a Function
will throw an exception because method and function names can't contain hyphens or spaces and when a callback is made of an array, it must have exactly two arguments.
This more "relaxed" check allows to save creation of mocks that are not necessary for the logic of the test.
It worth noting that when doing something like [SomeClass::class, 'aMethod']
if the class SomeClass
is available, Brain Monkey checks it to have an accessible method named aMethod
, and raise an exception if not, but will not do any check if the class is not available.
The same applies when object instances are used for callbacks, for example, using as callback argument [$someObject, 'aMethod']
, the instance of $someObject
is checked to have an accessible method named aMethod
.
[Fixed] apply_filters
Default Behavior
apply_filters
Default BehaviorThe WordPress function apply_filters()
is defined by Brain Monkey and it returns the first argument passed to it, just like WordPress:
In Brain Monkey v1 this was true unless some expectation was added to the applied filter:
The test above fails in Brain Monkey v1. The reason is that even if the expectation in first line is validated, it breaks the default apply_filters
behavior, requiring the return value to be added to expectation to make the test pass again.
For example, the following test used to pass in Brain Monkey v1:
In Brain Monkey v2 this is not necessary anymore.
Calling expectApplied
on applied filters does not break the default behavior of apply_filters
behavior, if no return expectations are added.
The following test passes in Brain Monkey v2:
Please note that if any return expectation is added for a filter, return expectations must be added for all the set of arguments the filter might receive.
For example:
The second assertion fails because since we added a return expectation for the filter "'afilter'" we need to add return expectation for _all the possible arguments.
This task is easier in Brain Monkey v2 thanks to the introduction of andReturnFirstArg()
expectation method (more on this below).
For example:
andReturnFirstArg()
used in combination with Mockery methods zeroOrMoreTimes()->withAnyArgs()
allows to create a "catch all" behavior for filters when a return expectation has been added, without having to create specific expectations for each of the possible arguments a filter might receive.
Of course, adding specific expectations for each of the possible arguments a filter might receive is still possible.
[Added] Utility Functions Stubs
There are WordPress functions that are often used in WordPress plugins or themes that are pretty much logicless, but still they need to be mocked in tests if WordPress is not available.
Brain Monkey v2 now ships stubs for those functions, so it is not necessary to mock them anymore, they are:
__return_true
__return_false
__return_null
__return_empty_array
__return_empty_string
__return_zero
trailingslashit
untrailingslashit
Those functions do exactly what they are expected to do, even if WordPress is not loaded: some functions mocking is now saved.
Of course, their behavior can still be mocked, e.g. to make a test fail on purpose.
[Added] Support for doing_action()
and doing_filter()
doing_action()
and doing_filter()
When adding expectation on returning value of filters, or when using whenHappen
to respond to actions, inside the expectation callback, the function current_filter()
in Brain Monkey v1 used to correctly resolve to the action / filter being executed.
The functions doing_action()
and doing_filter()
didn't work: they were not provided at all with Brain Monkey v1 and required to be mocked "manually" .
In Brain Monkey v2 those two functions are provided as well, and correctly return true or false when used inside the callbacks used to respond to hooks.
[Added] Method andReturnFirstArg()
andReturnFirstArg()
When adding expectations on returning value of applied filters or functions, it is now possible to use andReturnFirstArg()
to make the Mockery expectations return first argument received.
[Added] Method andAlsoExpectIt()
andAlsoExpectIt()
In Mockery, when creating expectations for multiple methods of same class, the method getMock()
allows to do it without leaving "fluent interface chain", for example:
The method getMock()
is not available for Brain Monkey expectations.
For this reason has been introduced andAlsoExpectIt()
:
Of course, it also works in other kind of expectations, like for functions or for actions added or done.
[Added] New Exceptions Classes
In Brain Monkey v1, when exceptions were thrown, PHP core exception classes were used, like \RuntimeException
or \InvalidArgumentException
, and so on.
In Brain Monkey v2, different custom exceptions classes have been added, to make very easy to catch any error thrown by Brain Monkey.
Now, in fact, every exception thrown by Brain Monkey is of a custom type, and there's a hierarchy of exceptions classes for a total of 16 exception classes, all inheriting (one or more levels deep) the "base" exception class that is Brain\Monkey\Exception
.
Last updated