sras/mockaway

A package for mocking php objects for automated testing

dev-default 2014-05-01 07:19 UTC

This package is not auto-updated.

Last update: 2020-08-17 09:33:45 UTC


README

A mocking library for php

Instead of providing many obscure functions and many pages of documentation, Mockaway only provides a handful of constructs by which the user can create required mocking behaviours. This is intended to result in mock objects who's behavior is apparent from its definition itself, without having to refer the documentation.

Installing

Require this in your composer.json.

"sras/mockaway": "dev-default"

Usage

Every mock object returned from the library will have three public properties expect, replace and unmetExpectations. Properties expect and replace can be used to setup mock behaviour. And at any point, the unmetExpectations will contain the names of the expected methods that are yet to be called on object. The original constructor is never called.

To expect a call to a method with certain parameters, with out specifying a return value

<?php
$date_mock = Mockaway::Mock('Services\DateService');

// expect call to the method 'get' with argument 'now'
$date_mock->expect->get('now');

assert($date_mock->unmetExpectations === array('get'));

// after this call, the unmetExpectations is empty
$date_mock->get('now');
assert($date_mock->unmetExpectations === array());

One expectation will respond to exactly one and only one call. Further Calls will result in an UnexpectedCall exception being thrown.

To expect a call to a method with certain parameters and return a value

<?php
$date_mock = Mockaway::Mock('Services\DateService');

// expect call to the method 'get' with argument 'now' and return
// a fixed value
$date_mock->expect->get('now')->shouldReturn("2015-01-01");
assert($date_mock->unmetExpectations === array('get'));

// mock function returns the stored value
assert($date_mock->get('now') === '2015-01-01');

assert($date_mock->unmetExpectations === array());

As before, one expectation will respond to exactly one and only one call. Further Calls will result in an UnexpectedCall exception being thrown.

To check if all expected calls were received

If all the expected calls has been made on the mock object, the unmetExpectations will contain an empty array. If not, then it will contain the names of the methods that were not called as expected.

Respond to a call using a callback

Instead of returning a value, you can set a callback to be executed with the parameters, passed by the original call. This method does not track calls using unmetExpectations property. This will respond to any number of further calls to this method on the mock object.

<?php
$date_mock = Mockaway::Mock('Services\DateService');

// mock the get function to return a date two days after the passed date.
$date_mock->replace->get->with( function($str)  {
    $date= new DateTime($str, new DateTimeZone('GMT'));
    $date->modify("2 Days");
    return $date->format("Y-m-d");
});

assert( $date_mock->get("2015-01-01") === "2015-01-03");
// can be called any number of times
assert( $date_mock->get("2015-01-01") === "2015-01-03");
assert( $date_mock->get("2015-01-04") === "2015-01-06");

UnexpectedCall Exception

When the mock object is called with a method/parameter combination that it is not expecting, it will throw a UnexpectedCall Exception. You can use the getMethod and getArguments method of this exception to find out the exact call that triggered it.

Unexpectedcall Observers

The above mentioned UnexpectedCall exceptions may never reach the code that is expecting it, because some intermediate code caught them. So in order to make sure that you get all the unexpceted call information is to use observers. You can add an observer to a mock object using the unexpectedCallObservers array property of the mock object. An observer can either be a callable or an object with a "notify()" method. The observers will recive the \UnexpectedCall Exception object as its argument. So even if the actual exception was caught by an intermediate code you will still get the original exception via the notify call.

How it works?

When creating a mock, this library uses the reflection api to build the source code for a class that extends from the source object. The methods in this mock object will just contain calls to the objects stored in the expect and replace properties. These are the same objects that a user uses to setup expectations or behaviours using callback. When the mock object receives a call, it first checks the expect object to see if it has been setup to expect that exact call. If it has been, then it checks if a return value was specified and returns it if found. Else it returns null, and removes the call from the list of expected calls. If it does not find the call in the expect object, then it checks the replace object to see if there is a callback available. If yes, it calls the callback with the arguments and returns the return value. If not, it will throw the UnexpectedCall exception.

That's all!