Files
Leitgedanken/html2pdf-master/vendor/phake/phake/docs/method-verification.rst
aschwarz e2f1846f03 html2pdf
2023-05-12 12:27:19 +02:00

278 lines
11 KiB
ReStructuredText
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

.. _method-verification-section:
*******************
Method Verification
*******************
The ``Phake::verify()`` method is used to assert that method calls have been
made on a mock object that you can create with ``Phake::mock()``.
``Phake::verify()`` accepts the mock object you want to verify calls against.
Mock objects in Phake can almost be viewed as a tape recorder. Any time the code you are testing
calls a method on an object you create with ``Phake::mock()`` it is going to
record the method that you called along with all of the parameters used to call that method. Then
``Phake::verify()`` will look at that recording and allow you to assert whether
or not a certain call was made.
.. code-block:: php
class PhakeTest1 extends PHPUnit_Framework_TestCase
{
public function testBasicVerify()
{
$mock = Phake::mock('MyClass');
$mock->foo();
Phake::verify($mock)->foo();
}
}
The ``Phake::verify()`` call here, verifies that the method ``foo()`` has been called once (and only once) with no
parameters on the object ``$mock``. A very important thing to note here that is a departure from most (if not all)
other PHP mocking frameworks is that you want to verify the method call AFTER the method call takes place. Other
mocking frameworks such as the one built into PHPUnit depend on you setting the expectations of what will get called
prior to running the system under test.
Phake strives to allow you to follow the four phases of a unit test as laid out in xUnit Test Patterns: setup,
exercise, verify, and teardown. The setup phase of a test using Phake for mocking will now include calls to
``Phake::mock()`` for each class you want to mock. The exercise portion of your code will remain the same. The verify
section of your code will include calls to ``Phake::verify()``. The exercise and teardown phases will remain unchanged.
Verifying Method Parameters
===========================
Verifying method parameters using Phake is very simple yet can be very flexible. There are a wealth of options for
matching parameters that are discussed later on in :ref:`method-parameter-matchers-section`.
Verifying Multiple Invocations
==============================
A common need for mock objects is the ability to have variable multiple invocations on that object. Phake allows you to
use ``Phake::verify()`` multiple times on the same object. A notable difference between Phake and PHPUnits mocking
framework is the ability to mock multiple invocations of the same method with no regard for call sequences. The PHPUnit
mocking test below would fail for this reason.
.. code-block:: php
class MyTest extends PHPUnit_Framework_TestCase
{
public function testPHPUnitMock()
{
$mock = $this->getMock('PhakeTest_MockedClass');
$mock->expects($this->once())->method('fooWithArgument')
->with('foo');
$mock->expects($this->once())->method('fooWithArgument')
->with('bar');
$mock->fooWithArgument('foo');
$mock->fooWithArgument('bar');
}
}
The reason this test fails is because by default PHPUnit only allows a single expectation per method. The way you can
fix this is by using the `at()` matcher. This allows you to specify the index of the invocation you want to match
again. So to make the test above work you would have to change it.
.. code-block:: php
class MyTest extends PHPUnit_Framework_TestCase
{
public function testPHPUnitMock()
{
$mock = $this->getMock('PhakeTest_MockedClass');
//NOTICE this is now at() instead of once()
$mock->expects($this->at(0))->method('fooWithArgument')
->with('foo');
//NOTICE this is now at() instead of once()
$mock->expects($this->at(1))->method('fooWithArgument')
->with('bar');
$mock->fooWithArgument('foo');
$mock->fooWithArgument('bar');
}
}
This test will now run as expected. There is still one small problem however and that is that you are now testing not
just the invocations but also the order of invocations. Many times the order in which two calls are made really do not
matter. If swapping the order of two method calls will not break your application then there is no reason to enforce
that code structure through a unit test. Unfortunately, you cannot have multiple invocations of a method in PHPUnit
without enforcing call order. In Phake these two notions of call order and multiple invocations are kept completely
distinct. Here is the same test written using Phake.
.. code-block:: php
class MyTest extends PHPUnit_Framework_TestCase
{
public function testPHPUnitMock()
{
$mock = Phake::mock('PhakeTest_MockedClass');
$mock->fooWithArgument('foo');
$mock->fooWithArgument('bar');
Phake::verify($mock)->fooWithArgument('foo');
Phake::verify($mock)->fooWithArgument('bar');
}
}
You can switch the calls around in this example as much as you like and the test will still pass. You can mock as many
different invocations of the same method as you need.
If you would like to verify the exact same parameters are used on a method multiple times (or they all match the same
constraints multiple times) then you can use the verification mode parameter of ``Phake::verify()``. The second
parameter to ``Phake::verify()`` allows you to specify how many times you expect that method to be called with matching
parameters. If no value is specified then the default of one is used. The other options are:
* ``Phake::times($n)`` Where ``$n`` equals the exact number of times you expect the method to be called.
* ``Phake::atLeast($n)`` Where ``$n`` is the minimum number of times you expect the method to be called.
* ``Phake::atMost($n)`` Where ``$n`` is the most number of times you would expect the method to be called.
* ``Phake::never()`` - Same as calling ``Phake::times(0)``.
Here is an example of this in action.
.. code-block:: php
class MyTest extends PHPUnit_Framework_TestCase
{
public function testPHPUnitMock()
{
$mock = Phake::mock('PhakeTest_MockedClass');
$mock->fooWithArgument('foo');
$mock->fooWithArgument('foo');
Phake::verify($mock, Phake::times(2))->fooWithArgument('foo');
}
}
Verifying Calls Happen in a Particular Order
============================================
Sometimes the desired behavior is that you verify calls happen in a particular order. Say there is a functional reason
for the two variants of ``fooWithArgument()`` to be called in the order of the original test. You can utilize
``Phake::inOrder()`` to ensure the order of your call invocations. ``Phake::inOrder()`` takes one or more arguments and
errors out in the event that one of the verified calls was invoked out of order. The calls dont have to be in exact
sequential order, there can be other calls in between, it just ensures the specified calls themselves are called in
order relative to each other. Below is an example Phake test that behaves similarly to the PHPUnit test that utilized
``at()``.
.. code-block:: php
class MyTest extends PHPUnit_Framework_TestCase
{
public function testPHPUnitMock()
{
$mock = Phake::mock('PhakeTest_MockedClass');
$mock->fooWithArgument('foo');
$mock->fooWithArgument('bar');
Phake::inOrder(
Phake::verify($mock)->fooWithArgument('foo'),
Phake::verify($mock)->fooWithArgument('bar')
);
}
}
Verifying No Interaction with a Mock so Far
===========================================
Occasionally you may want to ensure that no interactions have occurred with a mock object. This can be done
by passing your mock object to ``Phake::verifyNoInteraction($mock)``. This will not prevent further interaction
with your mock, it will simply tell you whether or not any interaction up to that point has happened. You
can pass multiple arguments to this method to verify no interaction with multiple mock objects.
Verifying No Further Interaction with a Mock
============================================
There is a similar method to prevent any future interaction with a mock. This can be done by passing a mock
object to ``Phake::verifyNoFurtherInteraction($mock)``. You can pass multiple arguments to this method to
verify no further interaction occurs with multiple mock objects.
Verifying No Unverified Interaction with a Mock
============================================
By default any unverified calls to a mock are ignored. That is to say, if a call is made to `$mock->foo()` but
`Phake::verify($mock)->foo()` is never used, then no failures are thrown. If you want to be stricter and ensure that
all calls have been verified you can call `Phake::verifyNoOtherInteractions($mock)` at the end of your test. This will
check and make sure that all calls to your mock have been verified by one or more calls to Phake verify. This method
should only be used in those cases where you can clearly say that it is important that your test knows about all calls
on a particular object. One useful case for instance could be in testing a method that returns a filtered array.
.. code-block:: php
class FilterTest {
public function testFilteredList()
{
$filter = new MyFilter();
$list = Phake::Mock('MyList');
$filter->addEvenToList(array(1, 2, 3, 4, 5), $list);
Phake::verify($list)->push(2);
Phake::verify($list)->push(4);
Phake::verifyNoOtherInteractions($list);
}
}
Without `Phake::verifyNoOtherInteractions($list)` you would have to add additional verifications that `$list->push()`
was not called for the odd values in the list. This method should be used only when necessary. Using it in every test
is an anti-pattern that will lead to brittle tests.
Verifying Magic Methods
=======================
Most magic methods can be verified using the method name just like you would any other method. The one exception to this
is the ``__call()`` method. This method is overwritten on each mock already to allow for the fluent api that Phake
utilizes. If you want to verify a particular invocation of ``__call()`` you can verify the actual method call by
mocking the method passed in as the first parameter.
Consider the following class.
.. code-block:: php
class MagicClass
{
public function __call($method, $args)
{
return '__call';
}
}
You could mock an invocation of the `__call()` method through a userspace call to magicCall() with the following code.
.. code-block:: php
class MagicClassTest extends PHPUnit_Framework_TestCase
{
public function testMagicCall()
{
$mock = Phake::mock('MagicClass');
$mock->magicCall();
Phake::verify($mock)->magicCall();
}
}
If for any reason you need to explicitly verify calls to ``__call()`` then you can use ``Phake::verifyCallMethodWith()``.
.. code-block:: php
class MagicClassTest extends PHPUnit_Framework_TestCase
{
public function testMagicCall()
{
$mock = Phake::mock('MagicClass');
$mock->magicCall(42);
Phake::verifyCallMethodWith('magicCall', array(42))->isCalledOn($mock);
}
}