When I first joined Box, I had to convince people that mocking out important side effects (note: not implementation details) of your code was an important aspect of testing. And then we ran into PHPUnit's mocking syntax. "Ugh".

Finding this incredibly annoying, we decided to look at alternatives. We briefly considered Etsy's Mockery and Phake. Both of these have advantages over the built-in syntax but neither really did it for us. Our requirements were

Un-invasive: It should take the smallest amount of work possible to set up

Type Safety: We didn't want to sacrifice type safety when mocking in order to get an easier syntax.

Record/Replay/Verify: A few of us had a good experience in the Java world using EasyMock. We liked that it forced a test writer to divide their assembly step (record) from their act step (replay) and their assertion phase (verify). The AAA model helps with test readability significantly.So here's what we came up with:[php]
<?php

The 'shmock' function takes a class name and a closure that is used to configure expectations. We take advantage of PHP's anonymous function capability and use it to provide a "record" phase. The $email_service returned is a vanilla PHPUnit mock object which will be automatically verified by PHPUnit, just as before.

There are a couple things I really like about this. Remember this line?

Any guesses on what it means? The purpose of this is actually to disable the original constructor of the Email_Service object. Obviously. Inside the shmock closure, this looks like:

[php]
$email_service->disable_original_constructor();
[/php]

Although PHPUnit provides an alternate mock builder syntax, it's very poorly documented. As a result, most developers first see the getMock method and leave 'gems' like the above getMock() call in our testing code base.

We also have an opportunity to prevent common programming errors. When doing partial mocking (replacing some, but not all methods on an object) a common pitfall is to mock a private method. Because of how typesafe mocking must work in PHP, you cannot mock private methods. This is because a dynamic subclass of the target is evaluated at runtime - and since private methods cannot be overloaded, an attempt to mock a private method will not work.

PHPUnit does not provide any warning of this. Nor does it warn you when you've mocked a method that doesn't exist in a class. If duck typing is your thing, that's cool, but PHP's schizophrenic approach to type safety makes me want less flexibility, not more. So shmock will give you better messaging if you try to mock a method that ain't gonna work.

[code]
$ phpunit test
PHPUnit 3.6.11 by Sebastian Bergmann.

....F.

Time: 1 second, Memory: 3.00Mb

There was 1 failure:

1) Shmock\Shmock_Test::test_mocking_a_private_method_throws_exception
Attempted to expect #you_cant_mock_this, which is not defined or is a static method in the
class Shmock_Foo.
If you wish to disable this check, call $shmock-&gt;disable_strict_method_checking()
Failed asserting that false is true.
[/code]

If you'd like to use Shmock on your project, have a look at our documentation on the Github repo. We're happy to be contributing this to the community - if you have questions / comments, feel free to add a comment here!