Mokka PHP Mocking Framework¶
Index¶
Installation¶
Composer¶
Simply add belanur/mokka to the composer.json of your project. Use “dev-master” for the latest version:
{
"require-dev": {
"belanur/mokka": "dev-master"
}
}
Checking out the latest sources¶
Mokka sources are available on GitHub. Simply clone them and checkout the desired branch (master should be fine in most cases):
$ git clone https://github.com/belanur/mokka
Cloning into 'mokka'...
remote: Counting objects: 745, done.
remote: Compressing objects: 100% (107/107), done.
remote: Total 745 (delta 59), reused 0 (delta 0)
Receiving objects: 100% (745/745), 101.76 KiB | 0 bytes/s, done.
Resolving deltas: 100% (395/395), done.
Checking connectivity... done
$
If you want to contribute to Mokka, fork it!
Creating Mocks¶
Mocks are created with Mokka::mock() along with the name of the class that you want to mock. Starting with PHP 5.5 you can use the ‘class’ keyword, which is highly recommended for better refactoring support.
<?php
$mock = Mokka::mock(SampleClass::class);
If you are using PHP 5.4 (which is the minimum required for Mokka), you can alternatively pass the class name as a string.
<?php
$mock = Mokka::mock('SampleClass');
The huge drawback of this is that your IDE won’t recognize this as a class name, meaning your mocks will break if you rename ‘SampleClass’ to something else with a refactoring tool.
Mocking¶
Mocking a method lets you verify that a method was called with the given arguments.
<?php
$mock = Mokka::mock(SampleClass::class);
// Verify sure that the method getBar() gets called once
Mokka::verify($mock)->getBar();
You can use optional Invokation Rules with Mokka::verify():
<?php
// Verify sure that the method getBar() is never called
Mokka::verify($mock, Mokka::never())->getBar();
// Make sure getBar() gets called at least twice
Mokka::verify($mock, Mokka::atLeast(2)->getBar();
// Make sure getBar() gets called exactly three times
Mokka::verify($mock, Mokka::exactly(3)->getBar();
You can add multiple mocks for a single method with different arguments
<?php
// Make sure getBar() gets called once with the argument 'foo' and once with argument 'bar'
Mokka::verify($mock)->getBar('foo');
Mokka::verify($mock)->getBar('bar');
AnythingArgument¶
There is also a special AnythingArgument, so you don’t have to verify every single argument if it is not relevant for your test.
<?php
// Make sure getBar() gets called with the second argument 'foo'. The first argument can be anything.
Mokka::verify($mock)->getBar(Mokka::anything(), 'foo');
Stubbing¶
Stubbing a method lets you define a return value. A stubbed method does not have an Invokation Rule (like mocked methods), so if a stubbed method is not called, no exception is thrown.
<?php
$mock = Mokka::mock(SampleClass::class);
// getFoo() should return 'baz' when called with the argument 'bar'
Mokka::when($mock)->getFoo('bar')->thenReturn('baz');
echo $mock->getFoo(): // => NULL
echo $mock->getFoo('bar'); // => 'baz'
You can also use the special AnythingArgument introduced in Mocking here:
<?php
// getFoo() should always return 'baz'
Mokka::when($mock)->getFoo(Mokka::anything())->thenReturn('baz');
echo $mock->getFoo('foo'): // => 'baz'
echo $mock->getFoo('bar'); // => 'baz'
Combining Stubs and Mocks¶
You can combine mocks and stubs if you want to verify that a method gets called and also want to set a return value:
<?php
$mock = Mokka::mock(SampleClass::class);
// getFoo() should return 'baz' when called with the argument 'bar'
Mokka::when($mock)->getFoo('bar')->thenReturn('baz');
// also make sure that getFoo() gets called once
Mokka::verify($mock)->getFoo('bar');
echo $mock->getFoo('bar'); // => 'baz'
Throwing Exceptions¶
A stubbed method can throw an exception instead of returning a value:
<?php
$mock = Mokka::mock(SampleClass::class);
Mokka::when($mock)->getFoo()->thenThrow(new \InvalidArgumentException());
$mock->getBar(); // => throws exception
Mokka with PHPUnit¶
Mokka comes with the MokkaTestCase class, which provides easy access to mocking functions and adds support for PHPUnit
<?php
class FooTest extends MokkaTestCase
{
public function testFoo()
{
$mock = $this->mock(SampleClass::class);
$foo = new Foo($mock);
}
}