# Mock/Spy
Mock functions or "spies", let you spy on the behaviour of a function that is called indirectly by some other code.
Mocks are created using the mock function, and can be also used to mock a class. While, to create spies use the spyOn syntax.
# Methods
- getCallable()
- mockClear()
- mockRestore()
- mockImplementation(function)
- mockImplementationOnce(function)
- mockReturnValue(value)
- mockReturnValueOnce(value)
# Reference
# getCallable()
Returns the spy function for the mock. You can call this directly or pass as callback. It will automatically take care of running the original function, or the mocked implementation for you. And, will also record all the invocations and their parameters.
<?php
$func = func();
func(); // this is wrong, $func is not a callable
func()->getCallable()(); // returns null by default
# mockClear()
Reset only the information about the calls spied by the mock. This is useful when you want to clean up a mock's usage data between two assertions.
# mockRestore()
Does everything mockClear
does, and also restore the original (non-mocked) implementation.
This is useful when you want to mock functions in certain test cases and restore the original implementation in others.
mockRestore
works for mocks created with spyOn
, func
and mock
, but it has a different behaviour for each of them.
# Restore a spy
Restoring a spy clear the calls history and removes the custom implementations/return values. You'll be still able to spy the function calls, and re-mock the implementation again.
<?php
/* spyOn */
$spy = \Verde\spyOn('strlen');
$spy->mockImplementation(function() { return 'ciao'; });
strlen('whatever'); // return "ciao"
// Restore the original function
$spy->mockRestore();
strlen('whatever'); // return 8
# Restore a mock
Restoring a mock clear the calls history and restore the custom implementation, if passed during the creation.
<?php
/* with custom implementation */
$func = func(function() { return 42; });
$func->mockImplementation(function() { return 'ciao'; });
$func->getCallable()(); // return "ciao"
// restore the custom implementation
$func->mockRestore();
func(); // returns "42"
/* without custom implementation */
$func = func();
$func->mockImplementation(function() { return 'ciao'; });
$func->getCallable()(); // return "ciao"
// restore the custom implementation
$func->mockRestore();
func(); // returns "null" by default
# Restore a class mock
Restoring a class mock clear the calls history and restore the original class methods, this means that you won't be able to keep spying on its method, unless you mock it again.
<?php
/* without custom mocked methods */
$mock = mock(DummyClass:class);
// this execute the mock function automatically generated during the mock
DummyClass->doSomething();
// restore the original class
$mock->mockRestore();
// execute the original method
DummyClass->doSomething();
/* without custom mocked methods */
$doSomethingMock = func(function() { return 42; });
$mock = mock(DummyClass::class, [
'doSomething' => $doSomethingMock,
]);
// executes the $doSomethingMock
DummyClass->doSomething(); // returns 42
// this does NOT restore the original 'doSomething' method of the class
$doSomethingMock->mockRestore();
// this still returns 42!
DummyClass->doSomething();
NOTE: Class mocks are not destroyed automatically, so you must restore them manually at the end of your test.
# mockImplementation(function)
Accepts a function that should be used as the implementation of the mock. The mock itself will still record all calls made to it.
mockImplementation
works for mocks created with spyOn
or func
.
<?php
$spy = spyOn('strlen');
$spy->mockImplementation(function() { return 'ciao'; });
strlen('whatever'); // returns "ciao"
// or
$func = func();
$func->mockImplementation(function() { return 'ciao'; });
$func->getCallable()(); // return "ciao"
# mockImplementationOnce(function)
Accepts a function that will be used as an implementation of the mock for one call to the mocked function. Can be chained so that multiple function calls produce different results.
mockImplementationOnce
works for mocks created with spyOn
or func
.
<?php
$spy = spyOn('strlen');
$spy->mockImplementationOnce(function() { return 'ciao'; });
strlen('whatever'); // returns "ciao"
strlen('whatever'); // returns 8
// or
$spy = spyOn('strlen')
->mockImplementationOnce(function() { return 'ciao'; })
->mockImplementationOnce(function() { return 'hello'; });
strlen('whatever'); // returns "ciao"
strlen('whatever'); // returns "hello"
strlen('whatever'); // returns 8
NOTE: When the mocked function runs out of implementations defined with mockImplementationOnce,
it will execute the original (for spyOn
) or default (for func
) implementation.
# mockReturnValue(value)
Accepts a value that will be returned whenever the mock function is called.
mockReturnValue
works for mocks created with spyOn
or func
.
<?php
$spy = spyOn('strlen');
$spy->mockReturnValue("ciao");
strlen('whatever'); // returns "ciao"
strlen('whatever'); // returns 8
# mockReturnValueOnce(value)
Accepts a value that will be returned for one call to the mock function. Can be chained so that successive calls to the mock function return different values. When there are no more mockReturnValueOnce values to use, calls will return a value specified by mockReturnValue or will call the original implementation.
mockReturnValueOnce
works for mocks created with spyOn
or func
.
<?php
$spy = spyOn('strlen');
$spy->mockReturnValueOnce("ciao");
strlen('whatever'); // returns "ciao"
strlen('whatever'); // returns 8
// no more return values
$spy = spyOn('strlen')
->mockReturnValueOnce("ciao")
->mockReturnValueOnce("hello");
strlen('whatever'); // returns "ciao"
strlen('whatever'); // returns "hello"
strlen('whatever'); // returns 8
// custom mockReturnValue
$spy = spyOn('strlen')
->mockReturnValue("ciao")
->mockReturnValueOnce("hello");
strlen('whatever'); // returns "ciao"
strlen('whatever'); // returns "hello"
strlen('whatever'); // returns "ciao" (for this and next calls, unless the mock is restored).
NOTE: When the mocked function runs out of mocked return values it will use the mockReturnValue
information.
If the latter has not been specified, it will then fallback on the original function (for spyOn
) or default implementation (for func
).