One Hat Cyber Team
Your IP:
216.73.216.104
Server IP:
198.54.114.155
Server:
Linux server71.web-hosting.com 4.18.0-513.18.1.lve.el8.x86_64 #1 SMP Thu Feb 22 12:55:50 UTC 2024 x86_64
Server Software:
LiteSpeed
PHP Version:
5.6.40
Create File
|
Create Folder
Execute
Dir :
~
/
proc
/
self
/
root
/
proc
/
self
/
root
/
proc
/
self
/
cwd
/
View File Name :
docs.tar
en/index.rst 0000644 00000000214 15107322020 0006774 0 ustar 00 Common Documentation ==================== Welcome to the Doctrine Common Library documentation. .. toctree:: :depth: 2 :glob: * webhook.md 0000644 00000004006 15107406537 0006534 0 ustar 00  # Process realtime status updates with a webhook A webhook is a URL Mollie will call when an object’s status changes, for example when a payment changes from `open` to `paid`. More specifics can be found in [the webhook guide](https://docs.mollie.com/guides/webhooks). To implement the webhook in your Laravel application you need to provide a `webhookUrl` parameter when creating a payment (or subscription): ```php $payment = Mollie::api()->payments()->create([ 'amount' => [ 'currency' => 'EUR', 'value' => '10.00', // You must send the correct number of decimals, thus we enforce the use of strings ], 'description' => 'My first API payment', 'redirectUrl' => 'https://webshop.example.org/order/12345/', 'webhookUrl' => route('webhooks.mollie'), ]); ``` And create a matching route and controller for the webhook in your application: ```php // routes/web.php Route::name('webhooks.mollie')->post('webhooks/mollie', 'MollieWebhookController@handle'); ``` ```php // App/Http/Controllers/MollieWebhookController.php class MollieWebhookController extends Controller { public function handle(Request $request) { if (! $request->has('id')) { return; } $payment = Mollie::api()->payments()->get($request->id); if ($payment->isPaid()) { // do your thing... } } } ``` Finally, it is _strongly advised_ to disable the `VerifyCsrfToken` middleware, which is included in the `web` middleware group by default. (Out of the box, Laravel applies the `web` middleware group to all routes in `routes/web.php`.) You can exclude URIs from the CSRF protection in the `app/Http/Middleware/VerifyCsrfToken.php` file: ```php /** * The URIs that should be excluded from CSRF verification. * * @var array */ protected $except = [ 'webhooks/mollie' ]; ``` If this solution does not work, open an [issue](https://github.com/mollie/laravel-mollie/issues) so we can assist you. mollie_connect.md 0000644 00000003730 15107406537 0010073 0 ustar 00  # Using Mollie Connect with Laravel Socialite (Oauth) [Mollie Connect](https://docs.mollie.com/oauth/overview) allows you to create apps for Mollie merchants via OAuth. ## Why should I use OAuth? Mollie Connect is built on the [OAuth standard](https://en.wikipedia.org/wiki/OAuth). The OAuth connection enables you to access other merchants’ accounts with their consent, without having to exchange API keys. Whether you are just looking to improve your customers’ experiences, to automate essential business processes, or to whitelabel our platform completely, it is all possible with OAuth. Our OAuth platform allows you to: - Create payments and refunds on behalf of merchants - Manage merchants’ website profiles - View a merchants’ transaction and settlement data - Show the next settlement and balance at Mollie in your app - Integrate merchants’ invoices from Mollie in your app - Charge merchants for payments initiated through your app ([application fees](https://docs.mollie.com/oauth/application-fees)) ## Installation Make sure the Laravel Socialite package is installed. Then update `config/services.php` by adding this to the array: ```php 'mollie' => [ 'client_id' => env('MOLLIE_CLIENT_ID', 'app_xxx'), 'client_secret' => env('MOLLIE_CLIENT_SECRET'), 'redirect' => env('MOLLIE_REDIRECT_URI'), ], ``` Then add the corresponding credentials (`MOLLIE_CLIENT_ID`, `MOLLIE_CLIENT_SECRET`, `MOLLIE_REDIRECT_URI`) to your `.env` file. ## Example usage ```php Route::get('login', function () { return Socialite::with('mollie') ->scopes(['profiles.read']) // Additional permission: profiles.read ->redirect(); }); Route::get('login_callback', function () { $user = Socialite::with('mollie')->user(); Mollie::api()->setAccessToken($user->token); return Mollie::api()->profiles()->page(); // Retrieve payment profiles available on the obtained Mollie account }); ``` recurring_and_direct_charge.md 0000644 00000005011 15107406537 0012560 0 ustar 00  # Mollie Recurring Here you can see an example of how easy it is to use [Mollie recurring](https://docs.mollie.com/payments/recurring) payments. ## Create a customer First of all you need to [create a new customer](https://docs.mollie.com/payments/recurring#payments-recurring-first-payment) (step 1), this is pretty straight forward ```php $customer = Mollie::api()->customers()->create([ 'name' => 'John Doe', 'email' => 'john@doe.com', ]); ``` ## Initial Payment After creating the user, you can [start a payment](https://docs.mollie.com/payments/recurring#payments-recurring-first-payment) (step 3), it's important to set `sequenceType` to `first`, this will generate a mandate on Mollie's end that can be used to do direct charges. Without setting the `method` the payment screen of Mollie will display your methods that support recurring payments. ```php $payment = Mollie::api()->payments()->create([ 'amount' => [ 'currency' => 'EUR', 'value' => '25.00', // You must send the correct number of decimals, thus we enforce the use of strings ], 'customerId' => $customer->id, 'sequenceType' => 'first', 'description' => 'My Initial Payment', 'redirectUrl' => 'https://domain.com/return', 'webhookUrl' => route('webhooks.mollie'), ]); // Redirect the user to Mollie's payment screen. return redirect($payment->getCheckoutUrl(), 303); ``` ## Direct Charge After doing the initial payment, you may [charge the users card/account directly](https://docs.mollie.com/payments/recurring#payments-recurring-charging-on-demand). Make sure there's a valid mandate connected to the customer. In case there are multiple mandates at least one should have `status` set to `valid`. Checking mandates is easy: ```php $mandates = Mollie::api()->mandates()->listFor($customer); ``` If any of the mandates is valid, charging the user is a piece of cake. Make sure `sequenceType` is set to `recurring`. ```php $payment = Mollie::api()->payments()->create([ 'amount' => [ 'currency' => 'EUR', 'value' => '25.00', // You must send the correct number of decimals, thus we enforce the use of strings ], 'customerId' => $customer->id, 'sequenceType' => 'recurring', 'description' => 'Direct Charge', 'webhookUrl' => route('webhooks.mollie'), ]); ``` Like any other payment, Mollie will call your webhook to register the payment status so don't forget to save the transaction id to your database. migration_instructions_v1_to_v2.md 0000644 00000003526 15107406537 0013440 0 ustar 00  # Migrating from Laravel-Mollie v1.x to v2 ### Step 1: Update composer dependencies Update `composer.json` to match this: ``` "require": { "mollie/laravel-mollie": "^2.0" } ``` Then run `composer update mollie/laravel-mollie`. ### Step 2: Reconfiguring the Mollie API key Setting the api key has been simplified. It now only requires you to set a single variable in your `.env` file. This is how you do it: - If you have a `mollie.php` file in your `config/` directory, remove it. - Add `MOLLIE_KEY=your_api_key_here` to your `.env` file. Use the test key for test mode, or the live key for live mode. - You can now remove the `MOLLIE_TEST_MODE`, `MOLLIE_KEY_TEST` and `MOLLIE_KEY_LIVE` variables from the .env file. ### Step 3: Changed package methods A few months ago Mollie launched the v2 API, along with an upgraded php core client. The v2 release of this Laravel-Mollie package leverages the new features of the v2 API. This also means some breaking changes have been introduced in this package. Some methods were removed: - `Mollie::api()->permissions()` - `Mollie::api()->organizations()` - `Mollie::api()->issuers()` These methods were renamed: - `Mollie::api()->customerMandates()` into `Mollie::api()->mandates()` - `Mollie::api()->customersPayments()` into `Mollie::api()->customerPayments()` - `Mollie::api()->customerSubscriptions()` into `Mollie::api()->subscriptions()` - `Mollie::api()->paymentsRefunds()` into `Mollie::api()->refunds()` Also, this method was added: - `Mollie::api()->invoices()` ### Step 4: Other changes More breaking changes were introduced with the new Mollie API. Read about it here in the [official migration docs](https://docs.mollie.com/migrating-v1-to-v2). ## Stuck? Feel free to open an [issue](https://github.com/mollie/laravel-mollie/issues). roadmap.md 0000644 00000004616 15107406537 0006530 0 ustar 00  # Laravel-Mollie Roadmap This roadmap lists all current and upcoming activity for the Laravel-Mollie package. Please submit an [issue](https://github.com/mollie/laravel-mollie/issues) if you have a suggestion for Laravel-Mollie specific functionality. ## Planned for next major release ### Provide default webhook The Laravel-Mollie package makes it easy to set up a new Mollie payment in your Laravel application. But right now, you'll need to implement the webhook yourself. We plan on providing a default webhook, which will trigger an Event when a payment status has been updated. This way, you'll only need to listen for the PaymentUpdatedEvent. Another solution may be to provide a default overridable controller, like Cashier has. Or to implement both events and the controller. ### Switch to MIT license Currently, the Laravel Mollie client has a *BSD 2-Clause "Simplified" License*. We're discussing switching to a *MIT* license, which is most common in Laravel packages. ## Other Laravel packages by Mollie Besides the Laravel-Mollie package, we're looking for other options to support you integrating Mollie in your Laravel applications. ### Explore Laravel Cashier support ("Laravel/Cashier-Mollie") Laravel Cashier is a very popular package for easily adding recurring payments to your Laravel application. We are exploring whether it's possible for Laravel Cashier to support Mollie. You can join the discussion [here](https://github.com/mollie/laravel-mollie/issues/41). ### Explore Laravel Spark support [Laravel Spark](https://spark.laravel.com/) is a commercial SAAS starter kit. By adding Cashier-Mollie support, new SAAS projects can be built rapidly on top of Mollie's subscription services. Laravel Spark leverages Laravel Cashier for subscription billing. When/If Cashier-Mollie is implemented, support for Laravel Spark would be a logical next topic for exploration. ### Explore Laravel Nova plugin options [Laravel Nova](https://nova.laravel.com/) is a powerful Laravel and Vue based CMS (commercial license). Launch of this new CMS is scheduled August 2018. Adoption rate is expected to be high; [Sander](https://github.com/sandervanhooft) expects Nova is going to blow a hole in other Laravel and PHP CMSes' market shares. A Laravel Nova plugin for Mollie could for example list and manage payments, and include a few dashboard cards. en/custom.rst 0000644 00000023616 15107410637 0007226 0 ustar 00 Custom Annotation Classes ========================= If you want to define your own annotations, you just have to group them in a namespace and register this namespace in the ``AnnotationRegistry``. Annotation classes have to contain a class-level docblock with the text ``@Annotation``: .. code-block:: php namespace MyCompany\Annotations; /** @Annotation */ class Bar { // some code } Inject annotation values ------------------------ The annotation parser checks if the annotation constructor has arguments, if so then it will pass the value array, otherwise it will try to inject values into public properties directly: .. code-block:: php namespace MyCompany\Annotations; /** * @Annotation * * Some Annotation using a constructor */ class Bar { private $foo; public function __construct(array $values) { $this->foo = $values['foo']; } } /** * @Annotation * * Some Annotation without a constructor */ class Foo { public $bar; } Optional: Constructors with Named Parameters -------------------------------------------- Starting with Annotations v1.11 a new annotation instantiation strategy is available that aims at compatibility of Annotation classes with the PHP 8 attribute feature. You need to declare a constructor with regular parameter names that match the named arguments in the annotation syntax. To enable this feature, you can tag your annotation class with ``@NamedArgumentConstructor`` (available from v1.12) or implement the ``Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation`` interface (available from v1.11 and deprecated as of v1.12). When using the ``@NamedArgumentConstructor`` tag, the first argument of the constructor is considered as the default one. Usage with the ``@NamedArgumentConstructor`` tag .. code-block:: php namespace MyCompany\Annotations; /** * @Annotation * @NamedArgumentConstructor */ class Bar implements NamedArgumentConstructorAnnotation { private $foo; public function __construct(string $foo) { $this->foo = $foo; } } /** Usable with @Bar(foo="baz") */ /** Usable with @Bar("baz") */ In combination with PHP 8's constructor property promotion feature you can simplify this to: .. code-block:: php namespace MyCompany\Annotations; /** * @Annotation * @NamedArgumentConstructor */ class Bar implements NamedArgumentConstructorAnnotation { public function __construct(private string $foo) {} } Usage with the ``Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation`` interface (v1.11, deprecated as of v1.12): .. code-block:: php namespace MyCompany\Annotations; use Doctrine\Common\Annotations\NamedArgumentConstructorAnnotation; /** @Annotation */ class Bar implements NamedArgumentConstructorAnnotation { private $foo; public function __construct(private string $foo) {} } /** Usable with @Bar(foo="baz") */ Annotation Target ----------------- ``@Target`` indicates the kinds of class elements to which an annotation type is applicable. Then you could define one or more targets: - ``CLASS`` Allowed in class docblocks - ``PROPERTY`` Allowed in property docblocks - ``METHOD`` Allowed in the method docblocks - ``FUNCTION`` Allowed in function dockblocks - ``ALL`` Allowed in class, property, method and function docblocks - ``ANNOTATION`` Allowed inside other annotations If the annotations is not allowed in the current context, an ``AnnotationException`` is thrown. .. code-block:: php namespace MyCompany\Annotations; /** * @Annotation * @Target({"METHOD","PROPERTY"}) */ class Bar { // some code } /** * @Annotation * @Target("CLASS") */ class Foo { // some code } Attribute types --------------- The annotation parser checks the given parameters using the phpdoc annotation ``@var``, The data type could be validated using the ``@var`` annotation on the annotation properties or using the ``@Attributes`` and ``@Attribute`` annotations. If the data type does not match you get an ``AnnotationException`` .. code-block:: php namespace MyCompany\Annotations; /** * @Annotation * @Target({"METHOD","PROPERTY"}) */ class Bar { /** @var mixed */ public $mixed; /** @var boolean */ public $boolean; /** @var bool */ public $bool; /** @var float */ public $float; /** @var string */ public $string; /** @var integer */ public $integer; /** @var array */ public $array; /** @var SomeAnnotationClass */ public $annotation; /** @var array<integer> */ public $arrayOfIntegers; /** @var array<SomeAnnotationClass> */ public $arrayOfAnnotations; } /** * @Annotation * @Target({"METHOD","PROPERTY"}) * @Attributes({ * @Attribute("stringProperty", type = "string"), * @Attribute("annotProperty", type = "SomeAnnotationClass"), * }) */ class Foo { public function __construct(array $values) { $this->stringProperty = $values['stringProperty']; $this->annotProperty = $values['annotProperty']; } // some code } Annotation Required ------------------- ``@Required`` indicates that the field must be specified when the annotation is used. If it is not used you get an ``AnnotationException`` stating that this value can not be null. Declaring a required field: .. code-block:: php /** * @Annotation * @Target("ALL") */ class Foo { /** @Required */ public $requiredField; } Usage: .. code-block:: php /** @Foo(requiredField="value") */ public $direction; // Valid /** @Foo */ public $direction; // Required field missing, throws an AnnotationException Enumerated values ----------------- - An annotation property marked with ``@Enum`` is a field that accepts a fixed set of scalar values. - You should use ``@Enum`` fields any time you need to represent fixed values. - The annotation parser checks the given value and throws an ``AnnotationException`` if the value does not match. Declaring an enumerated property: .. code-block:: php /** * @Annotation * @Target("ALL") */ class Direction { /** * @Enum({"NORTH", "SOUTH", "EAST", "WEST"}) */ public $value; } Annotation usage: .. code-block:: php /** @Direction("NORTH") */ public $direction; // Valid value /** @Direction("NORTHEAST") */ public $direction; // Invalid value, throws an AnnotationException Constants --------- The use of constants and class constants is available on the annotations parser. The following usages are allowed: .. code-block:: php namespace MyCompany\Entity; use MyCompany\Annotations\Foo; use MyCompany\Annotations\Bar; use MyCompany\Entity\SomeClass; /** * @Foo(PHP_EOL) * @Bar(Bar::FOO) * @Foo({SomeClass::FOO, SomeClass::BAR}) * @Bar({SomeClass::FOO_KEY = SomeClass::BAR_VALUE}) */ class User { } Be careful with constants and the cache ! .. note:: The cached reader will not re-evaluate each time an annotation is loaded from cache. When a constant is changed the cache must be cleaned. Usage ----- Using the library API is simple. Using the annotations described in the previous section, you can now annotate other classes with your annotations: .. code-block:: php namespace MyCompany\Entity; use MyCompany\Annotations\Foo; use MyCompany\Annotations\Bar; /** * @Foo(bar="foo") * @Bar(foo="bar") */ class User { } Now we can write a script to get the annotations above: .. code-block:: php $reflClass = new ReflectionClass('MyCompany\Entity\User'); $classAnnotations = $reader->getClassAnnotations($reflClass); foreach ($classAnnotations AS $annot) { if ($annot instanceof \MyCompany\Annotations\Foo) { echo $annot->bar; // prints "foo"; } else if ($annot instanceof \MyCompany\Annotations\Bar) { echo $annot->foo; // prints "bar"; } } You have a complete API for retrieving annotation class instances from a class, property or method docblock: Reader API ~~~~~~~~~~ Access all annotations of a class ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: php public function getClassAnnotations(\ReflectionClass $class); Access one annotation of a class ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: php public function getClassAnnotation(\ReflectionClass $class, $annotationName); Access all annotations of a method ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: php public function getMethodAnnotations(\ReflectionMethod $method); Access one annotation of a method ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: php public function getMethodAnnotation(\ReflectionMethod $method, $annotationName); Access all annotations of a property ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: php public function getPropertyAnnotations(\ReflectionProperty $property); Access one annotation of a property ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: php public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName); Access all annotations of a function ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: php public function getFunctionAnnotations(\ReflectionFunction $property); Access one annotation of a function ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: php public function getFunctionAnnotation(\ReflectionFunction $property, $annotationName); en/annotations.rst 0000644 00000023130 15107410637 0010240 0 ustar 00 Handling Annotations ==================== There are several different approaches to handling annotations in PHP. Doctrine Annotations maps docblock annotations to PHP classes. Because not all docblock annotations are used for metadata purposes a filter is applied to ignore or skip classes that are not Doctrine annotations. Take a look at the following code snippet: .. code-block:: php namespace MyProject\Entities; use Doctrine\ORM\Mapping AS ORM; use Symfony\Component\Validator\Constraints AS Assert; /** * @author Benjamin Eberlei * @ORM\Entity * @MyProject\Annotations\Foobarable */ class User { /** * @ORM\Id @ORM\Column @ORM\GeneratedValue * @dummy * @var int */ private $id; /** * @ORM\Column(type="string") * @Assert\NotEmpty * @Assert\Email * @var string */ private $email; } In this snippet you can see a variety of different docblock annotations: - Documentation annotations such as ``@var`` and ``@author``. These annotations are ignored and never considered for throwing an exception due to wrongly used annotations. - Annotations imported through use statements. The statement ``use Doctrine\ORM\Mapping AS ORM`` makes all classes under that namespace available as ``@ORM\ClassName``. Same goes for the import of ``@Assert``. - The ``@dummy`` annotation. It is not a documentation annotation and not ignored. For Doctrine Annotations it is not entirely clear how to handle this annotation. Depending on the configuration an exception (unknown annotation) will be thrown when parsing this annotation. - The fully qualified annotation ``@MyProject\Annotations\Foobarable``. This is transformed directly into the given class name. How are these annotations loaded? From looking at the code you could guess that the ORM Mapping, Assert Validation and the fully qualified annotation can just be loaded using the defined PHP autoloaders. This is not the case however: For error handling reasons every check for class existence inside the ``AnnotationReader`` sets the second parameter $autoload of ``class_exists($name, $autoload)`` to false. To work flawlessly the ``AnnotationReader`` requires silent autoloaders which many autoloaders are not. Silent autoloading is NOT part of the `PSR-0 specification <https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md>`_ for autoloading. This is why Doctrine Annotations uses its own autoloading mechanism through a global registry. If you are wondering about the annotation registry being global, there is no other way to solve the architectural problems of autoloading annotation classes in a straightforward fashion. Additionally if you think about PHP autoloading then you recognize it is a global as well. To anticipate the configuration section, making the above PHP class work with Doctrine Annotations requires this setup: .. code-block:: php use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\AnnotationRegistry; AnnotationRegistry::registerFile("/path/to/doctrine/lib/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php"); AnnotationRegistry::registerAutoloadNamespace("Symfony\Component\Validator\Constraint", "/path/to/symfony/src"); AnnotationRegistry::registerAutoloadNamespace("MyProject\Annotations", "/path/to/myproject/src"); $reader = new AnnotationReader(); AnnotationReader::addGlobalIgnoredName('dummy'); The second block with the annotation registry calls registers all the three different annotation namespaces that are used. Doctrine Annotations saves all its annotations in a single file, that is why ``AnnotationRegistry#registerFile`` is used in contrast to ``AnnotationRegistry#registerAutoloadNamespace`` which creates a PSR-0 compatible loading mechanism for class to file names. In the third block, we create the actual ``AnnotationReader`` instance. Note that we also add ``dummy`` to the global list of ignored annotations for which we do not throw exceptions. Setting this is necessary in our example case, otherwise ``@dummy`` would trigger an exception to be thrown during the parsing of the docblock of ``MyProject\Entities\User#id``. Setup and Configuration ----------------------- To use the annotations library is simple, you just need to create a new ``AnnotationReader`` instance: .. code-block:: php $reader = new \Doctrine\Common\Annotations\AnnotationReader(); This creates a simple annotation reader with no caching other than in memory (in php arrays). Since parsing docblocks can be expensive you should cache this process by using a caching reader. To cache annotations, you can create a ``Doctrine\Common\Annotations\PsrCachedReader``. This reader decorates the original reader and stores all annotations in a PSR-6 cache: .. code-block:: php use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\PsrCachedReader; $cache = ... // instantiate a PSR-6 Cache pool $reader = new PsrCachedReader( new AnnotationReader(), $cache, $debug = true ); The ``debug`` flag is used here as well to invalidate the cache files when the PHP class with annotations changed and should be used during development. .. warning :: The ``AnnotationReader`` works and caches under the assumption that all annotations of a doc-block are processed at once. That means that annotation classes that do not exist and aren't loaded and cannot be autoloaded (using the AnnotationRegistry) would never be visible and not accessible if a cache is used unless the cache is cleared and the annotations requested again, this time with all annotations defined. By default the annotation reader returns a list of annotations with numeric indexes. If you want your annotations to be indexed by their class name you can wrap the reader in an ``IndexedReader``: .. code-block:: php use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\IndexedReader; $reader = new IndexedReader(new AnnotationReader()); .. warning:: You should never wrap the indexed reader inside a cached reader, only the other way around. This way you can re-use the cache with indexed or numeric keys, otherwise your code may experience failures due to caching in a numerical or indexed format. Registering Annotations ~~~~~~~~~~~~~~~~~~~~~~~ As explained in the introduction, Doctrine Annotations uses its own autoloading mechanism to determine if a given annotation has a corresponding PHP class that can be autoloaded. For annotation autoloading you have to configure the ``Doctrine\Common\Annotations\AnnotationRegistry``. There are three different mechanisms to configure annotation autoloading: - Calling ``AnnotationRegistry#registerFile($file)`` to register a file that contains one or more annotation classes. - Calling ``AnnotationRegistry#registerNamespace($namespace, $dirs = null)`` to register that the given namespace contains annotations and that their base directory is located at the given $dirs or in the include path if ``NULL`` is passed. The given directories should *NOT* be the directory where classes of the namespace are in, but the base directory of the root namespace. The AnnotationRegistry uses a namespace to directory separator approach to resolve the correct path. - Calling ``AnnotationRegistry#registerLoader($callable)`` to register an autoloader callback. The callback accepts the class as first and only parameter and has to return ``true`` if the corresponding file was found and included. .. note:: Loaders have to fail silently, if a class is not found even if it matches for example the namespace prefix of that loader. Never is a loader to throw a warning or exception if the loading failed otherwise parsing doc block annotations will become a huge pain. A sample loader callback could look like: .. code-block:: php use Doctrine\Common\Annotations\AnnotationRegistry; use Symfony\Component\ClassLoader\UniversalClassLoader; AnnotationRegistry::registerLoader(function($class) { $file = str_replace("\\", DIRECTORY_SEPARATOR, $class) . ".php"; if (file_exists("/my/base/path/" . $file)) { // file_exists() makes sure that the loader fails silently require "/my/base/path/" . $file; } }); $loader = new UniversalClassLoader(); AnnotationRegistry::registerLoader(array($loader, "loadClass")); Ignoring missing exceptions ~~~~~~~~~~~~~~~~~~~~~~~~~~~ By default an exception is thrown from the ``AnnotationReader`` if an annotation was found that: - is not part of the list of ignored "documentation annotations"; - was not imported through a use statement; - is not a fully qualified class that exists. You can disable this behavior for specific names if your docblocks do not follow strict requirements: .. code-block:: php $reader = new \Doctrine\Common\Annotations\AnnotationReader(); AnnotationReader::addGlobalIgnoredName('foo'); PHP Imports ~~~~~~~~~~~ By default the annotation reader parses the use-statement of a php file to gain access to the import rules and register them for the annotation processing. Only if you are using PHP Imports can you validate the correct usage of annotations and throw exceptions if you misspelled an annotation. This mechanism is enabled by default. To ease the upgrade path, we still allow you to disable this mechanism. Note however that we will remove this in future versions: .. code-block:: php $reader = new \Doctrine\Common\Annotations\AnnotationReader(); $reader->setEnabledPhpImports(false); en/sidebar.rst 0000644 00000000101 15107410640 0007277 0 ustar 00 .. toctree:: :depth: 3 index annotations custom en/reference/class-loading.rst 0000644 00000022444 15107463116 0012370 0 ustar 00 Class Loading ============= Class loading is an essential part of any PHP application that makes heavy use of classes and interfaces. Unfortunately, a lot of people and projects spend a lot of time and effort on custom and specialized class loading strategies. It can quickly become a pain to understand what is going on when using multiple libraries and/or frameworks, each with its own way to do class loading. Class loading should be simple and it is an ideal candidate for convention over configuration. Overview -------- The Doctrine Common ClassLoader implements a simple and efficient approach to class loading that is easy to understand and use. The implementation is based on the widely used and accepted convention of mapping namespace and class names to a directory structure. This approach is used for example by Symfony2, the Zend Framework and of course, Doctrine. For example, the following class: .. code-block:: php <?php namespace MyProject\Shipping; class ShippingStrategy { ... } resides in the following directory structure: :: src/ /MyProject /Shipping ShippingStrategy.php Note that the name of "src" or the structure above or beside this directory is completely arbitrary. "src" could be named "classes" or "lib" or whatever. The only convention to adhere to is to map namespaces to directories and classes to files named after the class name. Usage ----- To use a Doctrine Common ClassLoader, you first need to load the class file containing the ClassLoader. This is the only class file that actually needs to be loaded explicitly via ``require``. All other classes will be loaded on demand by the configured class loaders. .. code-block:: php <?php use Doctrine\Common\ClassLoader; require '/path/to/Doctrine/Common/ClassLoader.php'; $classLoader = new ClassLoader('MyProject', '/path/to/src'); A ``ClassLoader`` takes two constructor parameters, both optional. In the normal case both arguments are supplied. The first argument specifies the namespace prefix this class loader should be responsible for and the second parameter is the path to the root directory where the classes can be found according to the convention mentioned previously. The class loader in the example above would thus be responsible for all classes under the 'MyProject' namespace and it would look for the class files starting at the directory '/path/to/src'. Also note that the prefix supplied in the first argument need not be a root namespace but can be an arbitrarily nested namespace as well. This allows you to even have the sources of subnamespaces split across different directories. For example, all projects under the Doctrine umbrella reside in the Doctrine namespace, yet the sources for each project usually do not reside under a common root directory. The following is an example of configuring three class loaders, one for each used Doctrine project: .. code-block:: php <?php use Doctrine\Common\ClassLoader; require '/path/to/Doctrine/Common/ClassLoader.php'; $commonLoader = new ClassLoader('Doctrine\Common', '/path/to/common/lib'); $dbalLoader = new ClassLoader('Doctrine\DBAL', '/path/to/dbal/lib'); $ormLoader = new ClassLoader('Doctrine\ORM', '/path/to/orm/lib'); $commonLoader->register(); $dbalLoader->register(); $ormLoader->register(); Do not be afraid of using multiple class loaders. Due to the efficient class loading design you will not incur much overhead from using many class loaders. Take a look at the implementation of ``ClassLoader#loadClass`` to see how simple and efficient the class loading is. The iteration over the installed class loaders happens in C (with the exception of using ``ClassLoader::classExists``). A ClassLoader can be used in the following other variations, however, these are rarely used/needed: - If only the second argument is not supplied, the class loader will be responsible for the namespace prefix given in the first argument and it will rely on the PHP include_path. - If only the first argument is not supplied, the class loader will be responsible for *all* classes and it will try to look up *all* classes starting at the directory given as the second argument. - If both arguments are not supplied, the class loader will be responsible for *all* classes and it will rely on the PHP include_path. File Extension -------------- By default, a ClassLoader uses the ``.php`` file extension for all class files. You can change this behavior, for example to use a ClassLoader to load classes from a library that uses the ".class.php" convention (but it must nevertheless adhere to the directory structure convention!): .. code-block:: php <?php $customLoader = new ClassLoader('CustomLib', '/path/to/custom/lib'); $customLoader->setFileExtension('.class.php'); $customLoader->register(); Namespace Separator ------------------- By default, a ClassLoader uses the ``\`` namespace separator. You can change this behavior, for example to use a ClassLoader to load legacy Zend Framework classes that still use the underscore "_" separator: .. code-block:: php <?php $zend1Loader = new ClassLoader('Zend', '/path/to/zend/lib'); $zend1Loader->setNamespaceSeparator('_'); $zend1Loader->register(); Failing Silently and class_exists ---------------------------------- A lot of class/autoloaders these days try to fail silently when a class file is not found. For the most part this is necessary in order to support using ``class_exists('ClassName', true)`` which is supposed to return a boolean value but triggers autoloading. This is a bad thing as it basically forces class loaders to fail silently, which in turn requires costly file_exists or fopen calls for each class being loaded, even though in at least 99% of the cases this is not necessary (compare the number of class_exists(..., true) invocations to the total number of classes being loaded in a request). The Doctrine Common ClassLoader does not fail silently, by design. It therefore does not need any costly checks for file existence. A ClassLoader is always responsible for all classes with a certain namespace prefix and if a class is requested to be loaded and can not be found this is considered to be a fatal error. This also means that using class_exists(..., true) to check for class existence when using a Doctrine Common ClassLoader is not possible but this is not a bad thing. What class\_exists(..., true) actually means is two things: 1) Check whether the class is already defined/exists (i.e. class_exists(..., false)) and if not 2) check whether a class file can be loaded for that class. In the Doctrine Common ClassLoader the two responsibilities of loading a class and checking for its existence are separated, which can be observed by the existence of the two methods ``loadClass`` and ``canLoadClass``. Thereby ``loadClass`` does not invoke ``canLoadClass`` internally, by design. However, you are free to use it yourself to check whether a class can be loaded and the following code snippet is thus equivalent to class\_exists(..., true): .. code-block:: php <?php // Equivalent to if (('Foo', true)) if there is only 1 class loader to check if (class_exists('Foo', false) || $classLoader->canLoadClass('Foo')) { // ... } The only problem with this is that it is inconvenient as you need to have a reference to the class loaders around (and there are often multiple class loaders in use). Therefore, a simpler alternative exists for the cases in which you really want to ask all installed class loaders whether they can load the class: ``ClassLoader::classExists($className)``: .. code-block:: php <?php // Equivalent to if (class_exists('Foo', true)) if (ClassLoader::classExists('Foo')) { // ... } This static method can basically be used as a drop-in replacement for class_exists(..., true). It iterates over all installed class loaders and asks each of them via ``canLoadClass``, returning early (with TRUE) as soon as one class loader returns TRUE from ``canLoadClass``. If this sounds like it can potentially be rather costly then because that is true but it is exactly the same thing that class_exists(..., true) does under the hood, it triggers a complete interaction of all class/auto loaders. Checking for class existence via invoking autoloading was never a cheap thing to do but now it is more obvious and more importantly, this check is no longer interleaved with regular class loading, which avoids having to check each and every class for existence prior to loading it. The vast majority of classes to be loaded are *not* optional and a failure to load such a class is, and should be, a fatal error. The ClassLoader design reflects this. If you have code that requires the usage of class\_exists(..., true) or ClassLoader::classExists during normal runtime of the application (i.e. on each request) try to refactor your design to avoid it. Summary ------- No matter which class loader you prefer to use (Doctrine classes do not care about how they are loaded), we kindly encourage you to adhere to the simple convention of mapping namespaces and class names to a directory structure. Class loading should be simple, automated and uniform. Time is better invested in actual application development than in designing special directory structures, autoloaders and clever caching strategies for class loading. PSR7-Usage.md 0000644 00000012564 15107716346 0006705 0 ustar 00 ### PSR-7 Usage All PSR-7 applications comply with these interfaces They were created to establish a standard between middleware implementations. > `RequestInterface`, `ServerRequestInterface`, `ResponseInterface` extend `MessageInterface` because the `Request` and the `Response` are `HTTP Messages`. > When using `ServerRequestInterface`, both `RequestInterface` and `Psr\Http\Message\MessageInterface` methods are considered. The following examples will illustrate how basic operations are done in PSR-7. ##### Examples For this examples to work (at least) a PSR-7 implementation package is required. (eg: zendframework/zend-diactoros, guzzlehttp/psr7, slim/slim, etc) All PSR-7 implementations should have the same behaviour. The following will be assumed: `$request` is an object of `Psr\Http\Message\RequestInterface` and `$response` is an object implementing `Psr\Http\Message\RequestInterface` ### Working with HTTP Headers #### Adding headers to response: ```php $response->withHeader('My-Custom-Header', 'My Custom Message'); ``` #### Appending values to headers ```php $response->withAddedHeader('My-Custom-Header', 'The second message'); ``` #### Checking if header exists: ```php $request->hasHeader('My-Custom-Header'); // will return false $response->hasHeader('My-Custom-Header'); // will return true ``` > Note: My-Custom-Header was only added in the Response #### Getting comma-separated values from a header (also applies to request) ```php // getting value from request headers $request->getHeaderLine('Content-Type'); // will return: "text/html; charset=UTF-8" // getting value from response headers $response->getHeaderLine('My-Custom-Header'); // will return: "My Custom Message; The second message" ``` #### Getting array of value from a header (also applies to request) ```php // getting value from request headers $request->getHeader('Content-Type'); // will return: ["text/html", "charset=UTF-8"] // getting value from response headers $response->getHeader('My-Custom-Header'); // will return: ["My Custom Message", "The second message"] ``` #### Removing headers from HTTP Messages ```php // removing a header from Request, removing deprecated "Content-MD5" header $request->withoutHeader('Content-MD5'); // removing a header from Response // effect: the browser won't know the size of the stream // the browser will download the stream till it ends $response->withoutHeader('Content-Length'); ``` ### Working with HTTP Message Body When working with the PSR-7 there are two methods of implementation: #### 1. Getting the body separately > This method makes the body handling easier to understand and is useful when repeatedly calling body methods. (You only call `getBody()` once). Using this method mistakes like `$response->write()` are also prevented. ```php $body = $response->getBody(); // operations on body, eg. read, write, seek // ... // replacing the old body $response->withBody($body); // this last statement is optional as we working with objects // in this case the "new" body is same with the "old" one // the $body variable has the same value as the one in $request, only the reference is passed ``` #### 2. Working directly on response > This method is useful when only performing few operations as the `$request->getBody()` statement fragment is required ```php $response->getBody()->write('hello'); ``` ### Getting the body contents The following snippet gets the contents of a stream contents. > Note: Streams must be rewinded, if content was written into streams, it will be ignored when calling `getContents()` because the stream pointer is set to the last character, which is `\0` - meaning end of stream. ```php $body = $response->getBody(); $body->rewind(); // or $body->seek(0); $bodyText = $body->getContents(); ``` > Note: If `$body->seek(1)` is called before `$body->getContents()`, the first character will be ommited as the starting pointer is set to `1`, not `0`. This is why using `$body->rewind()` is recommended. ### Append to body ```php $response->getBody()->write('Hello'); // writing directly $body = $request->getBody(); // which is a `StreamInterface` $body->write('xxxxx'); ``` ### Prepend to body Prepending is different when it comes to streams. The content must be copied before writing the content to be prepended. The following example will explain the behaviour of streams. ```php // assuming our response is initially empty $body = $repsonse->getBody(); // writing the string "abcd" $body->write('abcd'); // seeking to start of stream $body->seek(0); // writing 'ef' $body->write('ef'); // at this point the stream contains "efcd" ``` #### Prepending by rewriting separately ```php // assuming our response body stream only contains: "abcd" $body = $response->getBody(); $body->rewind(); $contents = $body->getContents(); // abcd // seeking the stream to beginning $body->rewind(); $body->write('ef'); // stream contains "efcd" $body->write($contents); // stream contains "efabcd" ``` > Note: `getContents()` seeks the stream while reading it, therefore if the second `rewind()` method call was not present the stream would have resulted in `abcdefabcd` because the `write()` method appends to stream if not preceeded by `rewind()` or `seek(0)`. #### Prepending by using contents as a string ```php $body = $response->getBody(); $body->rewind(); $contents = $body->getContents(); // efabcd $contents = 'ef'.$contents; $body->rewind(); $body->write($contents); ``` PSR7-Interfaces.md 0000644 00000022514 15107716346 0007720 0 ustar 00 # Interfaces The purpose of this list is to help in finding the methods when working with PSR-7. This can be considered as a cheatsheet for PSR-7 interfaces. The interfaces defined in PSR-7 are the following: | Class Name | Description | |---|---| | [Psr\Http\Message\MessageInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessagemessageinterface) | Representation of a HTTP message | | [Psr\Http\Message\RequestInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessagerequestinterface) | Representation of an outgoing, client-side request. | | [Psr\Http\Message\ServerRequestInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageserverrequestinterface) | Representation of an incoming, server-side HTTP request. | | [Psr\Http\Message\ResponseInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageresponseinterface) | Representation of an outgoing, server-side response. | | [Psr\Http\Message\StreamInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessagestreaminterface) | Describes a data stream | | [Psr\Http\Message\UriInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageuriinterface) | Value object representing a URI. | | [Psr\Http\Message\UploadedFileInterface](http://www.php-fig.org/psr/psr-7/#psrhttpmessageuploadedfileinterface) | Value object representing a file uploaded through an HTTP request. | ## `Psr\Http\Message\MessageInterface` Methods | Method Name | Description | Notes | |------------------------------------| ----------- | ----- | | `getProtocolVersion()` | Retrieve HTTP protocol version | 1.0 or 1.1 | | `withProtocolVersion($version)` | Returns new message instance with given HTTP protocol version | | | `getHeaders()` | Retrieve all HTTP Headers | [Request Header List](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields), [Response Header List](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields) | | `hasHeader($name)` | Checks if HTTP Header with given name exists | | | `getHeader($name)` | Retrieves a array with the values for a single header | | | `getHeaderLine($name)` | Retrieves a comma-separated string of the values for a single header | | | `withHeader($name, $value)` | Returns new message instance with given HTTP Header | if the header existed in the original instance, replaces the header value from the original message with the value provided when creating the new instance. | | `withAddedHeader($name, $value)` | Returns new message instance with appended value to given header | If header already exists value will be appended, if not a new header will be created | | `withoutHeader($name)` | Removes HTTP Header with given name| | | `getBody()` | Retrieves the HTTP Message Body | Returns object implementing `StreamInterface`| | `withBody(StreamInterface $body)` | Returns new message instance with given HTTP Message Body | | ## `Psr\Http\Message\RequestInterface` Methods Same methods as `Psr\Http\Message\MessageInterface` + the following methods: | Method Name | Description | Notes | |------------------------------------| ----------- | ----- | | `getRequestTarget()` | Retrieves the message's request target | origin-form, absolute-form, authority-form, asterisk-form ([RFC7230](https://www.rfc-editor.org/rfc/rfc7230.txt)) | | `withRequestTarget($requestTarget)` | Return a new message instance with the specific request-target | | | `getMethod()` | Retrieves the HTTP method of the request. | GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE (defined in [RFC7231](https://tools.ietf.org/html/rfc7231)), PATCH (defined in [RFC5789](https://tools.ietf.org/html/rfc5789)) | | `withMethod($method)` | Returns a new message instance with the provided HTTP method | | | `getUri()` | Retrieves the URI instance | | | `withUri(UriInterface $uri, $preserveHost = false)` | Returns a new message instance with the provided URI | | ## `Psr\Http\Message\ServerRequestInterface` Methods Same methods as `Psr\Http\Message\RequestInterface` + the following methods: | Method Name | Description | Notes | |------------------------------------| ----------- | ----- | | `getServerParams() ` | Retrieve server parameters | Typically derived from `$_SERVER` | | `getCookieParams()` | Retrieves cookies sent by the client to the server. | Typically derived from `$_COOKIES` | | `withCookieParams(array $cookies)` | Returns a new request instance with the specified cookies | | | `withQueryParams(array $query)` | Returns a new request instance with the specified query string arguments | | | `getUploadedFiles()` | Retrieve normalized file upload data | | | `withUploadedFiles(array $uploadedFiles)` | Returns a new request instance with the specified uploaded files | | | `getParsedBody()` | Retrieve any parameters provided in the request body | | | `withParsedBody($data)` | Returns a new request instance with the specified body parameters | | | `getAttributes()` | Retrieve attributes derived from the request | | | `getAttribute($name, $default = null)` | Retrieve a single derived request attribute | | | `withAttribute($name, $value)` | Returns a new request instance with the specified derived request attribute | | | `withoutAttribute($name)` | Returns a new request instance that without the specified derived request attribute | | ## `Psr\Http\Message\ResponseInterface` Methods: Same methods as `Psr\Http\Message\MessageInterface` + the following methods: | Method Name | Description | Notes | |------------------------------------| ----------- | ----- | | `getStatusCode()` | Gets the response status code. | | | `withStatus($code, $reasonPhrase = '')` | Returns a new response instance with the specified status code and, optionally, reason phrase. | | | `getReasonPhrase()` | Gets the response reason phrase associated with the status code. | | ## `Psr\Http\Message\StreamInterface` Methods | Method Name | Description | Notes | |------------------------------------| ----------- | ----- | | `__toString()` | Reads all data from the stream into a string, from the beginning to end. | | | `close()` | Closes the stream and any underlying resources. | | | `detach()` | Separates any underlying resources from the stream. | | | `getSize()` | Get the size of the stream if known. | | | `eof()` | Returns true if the stream is at the end of the stream.| | | `isSeekable()` | Returns whether or not the stream is seekable. | | | `seek($offset, $whence = SEEK_SET)` | Seek to a position in the stream. | | | `rewind()` | Seek to the beginning of the stream. | | | `isWritable()` | Returns whether or not the stream is writable. | | | `write($string)` | Write data to the stream. | | | `isReadable()` | Returns whether or not the stream is readable. | | | `read($length)` | Read data from the stream. | | | `getContents()` | Returns the remaining contents in a string | | | `getMetadata($key = null)()` | Get stream metadata as an associative array or retrieve a specific key. | | ## `Psr\Http\Message\UriInterface` Methods | Method Name | Description | Notes | |------------------------------------| ----------- | ----- | | `getScheme()` | Retrieve the scheme component of the URI. | | | `getAuthority()` | Retrieve the authority component of the URI. | | | `getUserInfo()` | Retrieve the user information component of the URI. | | | `getHost()` | Retrieve the host component of the URI. | | | `getPort()` | Retrieve the port component of the URI. | | | `getPath()` | Retrieve the path component of the URI. | | | `getQuery()` | Retrieve the query string of the URI. | | | `getFragment()` | Retrieve the fragment component of the URI. | | | `withScheme($scheme)` | Return an instance with the specified scheme. | | | `withUserInfo($user, $password = null)` | Return an instance with the specified user information. | | | `withHost($host)` | Return an instance with the specified host. | | | `withPort($port)` | Return an instance with the specified port. | | | `withPath($path)` | Return an instance with the specified path. | | | `withQuery($query)` | Return an instance with the specified query string. | | | `withFragment($fragment)` | Return an instance with the specified URI fragment. | | | `__toString()` | Return the string representation as a URI reference. | | ## `Psr\Http\Message\UploadedFileInterface` Methods | Method Name | Description | Notes | |------------------------------------| ----------- | ----- | | `getStream()` | Retrieve a stream representing the uploaded file. | | | `moveTo($targetPath)` | Move the uploaded file to a new location. | | | `getSize()` | Retrieve the file size. | | | `getError()` | Retrieve the error associated with the uploaded file. | | | `getClientFilename()` | Retrieve the filename sent by the client. | | | `getClientMediaType()` | Retrieve the media type sent by the client. | | > `RequestInterface`, `ServerRequestInterface`, `ResponseInterface` extend `MessageInterface` because the `Request` and the `Response` are `HTTP Messages`. > When using `ServerRequestInterface`, both `RequestInterface` and `Psr\Http\Message\MessageInterface` methods are considered. cookbook/big_parent_class.rst 0000644 00000003210 15110326463 0012400 0 ustar 00 .. index:: single: Cookbook; Big Parent Class Big Parent Class ================ In some application code, especially older legacy code, we can come across some classes that extend a "big parent class" - a parent class that knows and does too much: .. code-block:: php class BigParentClass { public function doesEverything() { // sets up database connections // writes to log files } } class ChildClass extends BigParentClass { public function doesOneThing() { // but calls on BigParentClass methods $result = $this->doesEverything(); // does something with $result return $result; } } We want to test our ``ChildClass`` and its ``doesOneThing`` method, but the problem is that it calls on ``BigParentClass::doesEverything()``. One way to handle this would be to mock out **all** of the dependencies ``BigParentClass`` has and needs, and then finally actually test our ``doesOneThing`` method. It's an awful lot of work to do that. What we can do, is to do something... unconventional. We can create a runtime partial test double of the ``ChildClass`` itself and mock only the parent's ``doesEverything()`` method: .. code-block:: php $childClass = \Mockery::mock('ChildClass')->makePartial(); $childClass->shouldReceive('doesEverything') ->andReturn('some result from parent'); $childClass->doesOneThing(); // string("some result from parent"); With this approach we mock out only the ``doesEverything()`` method, and all the unmocked methods are called on the actual ``ChildClass`` instance. cookbook/map.rst.inc 0000644 00000000423 15110326463 0010431 0 ustar 00 * :doc:`/cookbook/default_expectations` * :doc:`/cookbook/detecting_mock_objects` * :doc:`/cookbook/not_calling_the_constructor` * :doc:`/cookbook/mocking_hard_dependencies` * :doc:`/cookbook/class_constants` * :doc:`/cookbook/big_parent_class` * :doc:`/cookbook/mockery_on` cookbook/mocking_class_within_class.rst 0000644 00000010475 15110326463 0014477 0 ustar 00 .. index:: single: Cookbook; Mocking class within class .. _mocking-class-within-class: Mocking class within class ========================== Imagine a case where you need to create an instance of a class and use it within the same method: .. code-block:: php // Point.php <?php namespace App; class Point { public function setPoint($x, $y) { echo "Point (" . $x . ", " . $y . ")" . PHP_EOL; } } // Rectangle.php <?php namespace App; use App\Point; class Rectangle { public function create($x1, $y1, $x2, $y2) { $a = new Point(); $a->setPoint($x1, $y1); $b = new Point(); $b->setPoint($x2, $y1); $c = new Point(); $c->setPoint($x2, $y2); $d = new Point(); $d->setPoint($x1, $y2); $this->draw([$a, $b, $c, $d]); } public function draw($points) { echo "Do something with the points"; } } And that you want to test that a logic in ``Rectangle->create()`` calls properly each used thing - in this case calls ``Point->setPoint()``, but ``Rectangle->draw()`` does some graphical stuff that you want to avoid calling. You set the mocks for ``App\Point`` and ``App\Rectangle``: .. code-block:: php <?php class MyTest extends PHPUnit\Framework\TestCase { public function testCreate() { $point = Mockery::mock("App\Point"); // check if our mock is called $point->shouldReceive("setPoint")->andThrow(Exception::class); $rect = Mockery::mock("App\Rectangle")->makePartial(); $rect->shouldReceive("draw"); $rect->create(0, 0, 100, 100); // does not throw exception Mockery::close(); } } and the test does not work. Why? The mocking relies on the class not being present yet, but the class is autoloaded therefore the mock alone for ``App\Point`` is useless which you can see with ``echo`` being executed. Mocks however work for the first class in the order of loading i.e. ``App\Rectangle``, which loads the ``App\Point`` class. In more complex example that would be a single point that initiates the whole loading (``use Class``) such as:: A // main loading initiator |- B // another loading initiator | |-E | +-G | |- C // another loading initiator | +-F | +- D That basically means that the loading prevents mocking and for each such a loading initiator there needs to be implemented a workaround. Overloading is one approach, however it pollutes the global state. In this case we try to completely avoid the global state pollution with custom ``new Class()`` behavior per loading initiator and that can be mocked easily in few critical places. That being said, although we can't stop loading, we can return mocks. Let's look at ``Rectangle->create()`` method: .. code-block:: php class Rectangle { public function newPoint() { return new Point(); } public function create($x1, $y1, $x2, $y2) { $a = $this->newPoint(); $a->setPoint($x1, $y1); ... } ... } We create a custom function to encapsulate ``new`` keyword that would otherwise just use the autoloaded class ``App\Point`` and in our test we mock that function so that it returns our mock: .. code-block:: php <?php class MyTest extends PHPUnit\Framework\TestCase { public function testCreate() { $point = Mockery::mock("App\Point"); // check if our mock is called $point->shouldReceive("setPoint")->andThrow(Exception::class); $rect = Mockery::mock("App\Rectangle")->makePartial(); $rect->shouldReceive("draw"); // pass the App\Point mock into App\Rectangle as an alternative // to using new App\Point() in-place. $rect->shouldReceive("newPoint")->andReturn($point); $this->expectException(Exception::class); $rect->create(0, 0, 100, 100); Mockery::close(); } } If we run this test now, it should pass. For more complex cases we'd find the next loader in the program flow and proceed with wrapping and passing mock instances with predefined behavior into already existing classes. cookbook/mocking_hard_dependencies.rst 0000644 00000010570 15110326463 0014243 0 ustar 00 .. index:: single: Cookbook; Mocking Hard Dependencies Mocking Hard Dependencies (new Keyword) ======================================= One prerequisite to mock hard dependencies is that the code we are trying to test uses autoloading. Let's take the following code for an example: .. code-block:: php <?php namespace App; class Service { function callExternalService($param) { $externalService = new Service\External($version = 5); $externalService->sendSomething($param); return $externalService->getSomething(); } } The way we can test this without doing any changes to the code itself is by creating :doc:`instance mocks </reference/instance_mocking>` by using the ``overload`` prefix. .. code-block:: php <?php namespace AppTest; use Mockery as m; class ServiceTest extends \PHPUnit_Framework_TestCase { public function testCallingExternalService() { $param = 'Testing'; $externalMock = m::mock('overload:App\Service\External'); $externalMock->shouldReceive('sendSomething') ->once() ->with($param); $externalMock->shouldReceive('getSomething') ->once() ->andReturn('Tested!'); $service = new \App\Service(); $result = $service->callExternalService($param); $this->assertSame('Tested!', $result); } } If we run this test now, it should pass. Mockery does its job and our ``App\Service`` will use the mocked external service instead of the real one. The problem with this is when we want to, for example, test the ``App\Service\External`` itself, or if we use that class somewhere else in our tests. When Mockery overloads a class, because of how PHP works with files, that overloaded class file must not be included otherwise Mockery will throw a "class already exists" exception. This is where autoloading kicks in and makes our job a lot easier. To make this possible, we'll tell PHPUnit to run the tests that have overloaded classes in separate processes and to not preserve global state. That way we'll avoid having the overloaded class included more than once. Of course this has its downsides as these tests will run slower. Our test example from above now becomes: .. code-block:: php <?php namespace AppTest; use Mockery as m; /** * @runTestsInSeparateProcesses * @preserveGlobalState disabled */ class ServiceTest extends \PHPUnit_Framework_TestCase { public function testCallingExternalService() { $param = 'Testing'; $externalMock = m::mock('overload:App\Service\External'); $externalMock->shouldReceive('sendSomething') ->once() ->with($param); $externalMock->shouldReceive('getSomething') ->once() ->andReturn('Tested!'); $service = new \App\Service(); $result = $service->callExternalService($param); $this->assertSame('Tested!', $result); } } Testing the constructor arguments of hard Dependencies ------------------------------------------------------ Sometimes we might want to ensure that the hard dependency is instantiated with particular arguments. With overloaded mocks, we can set up expectations on the constructor. .. code-block:: php <?php namespace AppTest; use Mockery as m; /** * @runTestsInSeparateProcesses * @preserveGlobalState disabled */ class ServiceTest extends \PHPUnit_Framework_TestCase { public function testCallingExternalService() { $externalMock = m::mock('overload:App\Service\External'); $externalMock->allows('sendSomething'); $externalMock->shouldReceive('__construct') ->once() ->with(5); $service = new \App\Service(); $result = $service->callExternalService($param); } } .. note:: For more straightforward and single-process tests oriented way check :ref:`mocking-class-within-class`. .. note:: This cookbook entry is an adaption of the blog post titled `"Mocking hard dependencies with Mockery" <https://robertbasic.com/blog/mocking-hard-dependencies-with-mockery/>`_, published by Robert Basic on his blog. cookbook/index.rst 0000644 00000000421 15110326463 0010211 0 ustar 00 Cookbook ======== .. toctree:: :hidden: default_expectations detecting_mock_objects not_calling_the_constructor mocking_hard_dependencies class_constants big_parent_class mockery_on mocking_class_within_class .. include:: map.rst.inc cookbook/default_expectations.rst 0000644 00000001365 15110326463 0013324 0 ustar 00 .. index:: single: Cookbook; Default Mock Expectations Default Mock Expectations ========================= Often in unit testing, we end up with sets of tests which use the same object dependency over and over again. Rather than mocking this class/object within every single unit test (requiring a mountain of duplicate code), we can instead define reusable default mocks within the test case's ``setup()`` method. This even works where unit tests use varying expectations on the same or similar mock object. How this works, is that you can define mocks with default expectations. Then, in a later unit test, you can add or fine-tune expectations for that specific test. Any expectation can be set as a default using the ``byDefault()`` declaration. cookbook/class_constants.rst 0000644 00000011104 15110326463 0012303 0 ustar 00 .. index:: single: Cookbook; Class Constants Class Constants =============== When creating a test double for a class, Mockery does not create stubs out of any class constants defined in the class we are mocking. Sometimes though, the non-existence of these class constants, setup of the test, and the application code itself, it can lead to undesired behavior, and even a PHP error: ``PHP Fatal error: Uncaught Error: Undefined class constant 'FOO' in ...`` While supporting class constants in Mockery would be possible, it does require an awful lot of work, for a small number of use cases. Named Mocks ----------- We can, however, deal with these constants in a way supported by Mockery - by using :ref:`creating-test-doubles-named-mocks`. A named mock is a test double that has a name of the class we want to mock, but under it is a stubbed out class that mimics the real class with canned responses. Lets look at the following made up, but not impossible scenario: .. code-block:: php class Fetcher { const SUCCESS = 0; const FAILURE = 1; public static function fetch() { // Fetcher gets something for us from somewhere... return self::SUCCESS; } } class MyClass { public function doFetching() { $response = Fetcher::fetch(); if ($response == Fetcher::SUCCESS) { echo "Thanks!" . PHP_EOL; } else { echo "Try again!" . PHP_EOL; } } } Our ``MyClass`` calls a ``Fetcher`` that fetches some resource from somewhere - maybe it downloads a file from a remote web service. Our ``MyClass`` prints out a response message depending on the response from the ``Fetcher::fetch()`` call. When testing ``MyClass`` we don't really want ``Fetcher`` to go and download random stuff from the internet every time we run our test suite. So we mock it out: .. code-block:: php // Using alias: because fetch is called statically! \Mockery::mock('alias:Fetcher') ->shouldReceive('fetch') ->andReturn(0); $myClass = new MyClass(); $myClass->doFetching(); If we run this, our test will error out with a nasty ``PHP Fatal error: Uncaught Error: Undefined class constant 'SUCCESS' in ..``. Here's how a ``namedMock()`` can help us in a situation like this. We create a stub for the ``Fetcher`` class, stubbing out the class constants, and then use ``namedMock()`` to create a mock named ``Fetcher`` based on our stub: .. code-block:: php class FetcherStub { const SUCCESS = 0; const FAILURE = 1; } \Mockery::namedMock('Fetcher', 'FetcherStub') ->shouldReceive('fetch') ->andReturn(0); $myClass = new MyClass(); $myClass->doFetching(); This works because under the hood, Mockery creates a class called ``Fetcher`` that extends ``FetcherStub``. The same approach will work even if ``Fetcher::fetch()`` is not a static dependency: .. code-block:: php class Fetcher { const SUCCESS = 0; const FAILURE = 1; public function fetch() { // Fetcher gets something for us from somewhere... return self::SUCCESS; } } class MyClass { public function doFetching($fetcher) { $response = $fetcher->fetch(); if ($response == Fetcher::SUCCESS) { echo "Thanks!" . PHP_EOL; } else { echo "Try again!" . PHP_EOL; } } } And the test will have something like this: .. code-block:: php class FetcherStub { const SUCCESS = 0; const FAILURE = 1; } $mock = \Mockery::mock('Fetcher', 'FetcherStub') $mock->shouldReceive('fetch') ->andReturn(0); $myClass = new MyClass(); $myClass->doFetching($mock); Constants Map ------------- Another way of mocking class constants can be with the use of the constants map configuration. Given a class with constants: .. code-block:: php class Fetcher { const SUCCESS = 0; const FAILURE = 1; public function fetch() { // Fetcher gets something for us from somewhere... return self::SUCCESS; } } It can be mocked with: .. code-block:: php \Mockery::getConfiguration()->setConstantsMap([ 'Fetcher' => [ 'SUCCESS' => 'success', 'FAILURE' => 'fail', ] ]); $mock = \Mockery::mock('Fetcher'); var_dump($mock::SUCCESS); // (string) 'success' var_dump($mock::FAILURE); // (string) 'fail' cookbook/detecting_mock_objects.rst 0000644 00000000612 15110326463 0013574 0 ustar 00 .. index:: single: Cookbook; Detecting Mock Objects Detecting Mock Objects ====================== Users may find it useful to check whether a given object is a real object or a simulated Mock Object. All Mockery mocks implement the ``\Mockery\MockInterface`` interface which can be used in a type check. .. code-block:: php assert($mightBeMocked instanceof \Mockery\MockInterface); cookbook/mockery_on.rst 0000644 00000005753 15110326463 0011264 0 ustar 00 .. index:: single: Cookbook; Complex Argument Matching With Mockery::on Complex Argument Matching With Mockery::on ========================================== When we need to do a more complex argument matching for an expected method call, the ``\Mockery::on()`` matcher comes in really handy. It accepts a closure as an argument and that closure in turn receives the argument passed in to the method, when called. If the closure returns ``true``, Mockery will consider that the argument has passed the expectation. If the closure returns ``false``, or a "falsey" value, the expectation will not pass. The ``\Mockery::on()`` matcher can be used in various scenarios — validating an array argument based on multiple keys and values, complex string matching... Say, for example, we have the following code. It doesn't do much; publishes a post by setting the ``published`` flag in the database to ``1`` and sets the ``published_at`` to the current date and time: .. code-block:: php <?php namespace Service; class Post { public function __construct($model) { $this->model = $model; } public function publishPost($id) { $saveData = [ 'post_id' => $id, 'published' => 1, 'published_at' => gmdate('Y-m-d H:i:s'), ]; $this->model->save($saveData); } } In a test we would mock the model and set some expectations on the call of the ``save()`` method: .. code-block:: php <?php $postId = 42; $modelMock = \Mockery::mock('Model'); $modelMock->shouldReceive('save') ->once() ->with(\Mockery::on(function ($argument) use ($postId) { $postIdIsSet = isset($argument['post_id']) && $argument['post_id'] === $postId; $publishedFlagIsSet = isset($argument['published']) && $argument['published'] === 1; $publishedAtIsSet = isset($argument['published_at']); return $postIdIsSet && $publishedFlagIsSet && $publishedAtIsSet; })); $service = new \Service\Post($modelMock); $service->publishPost($postId); \Mockery::close(); The important part of the example is inside the closure we pass to the ``\Mockery::on()`` matcher. The ``$argument`` is actually the ``$saveData`` argument the ``save()`` method gets when it is called. We check for a couple of things in this argument: * the post ID is set, and is same as the post ID we passed in to the ``publishPost()`` method, * the ``published`` flag is set, and is ``1``, and * the ``published_at`` key is present. If any of these requirements is not satisfied, the closure will return ``false``, the method call expectation will not be met, and Mockery will throw a ``NoMatchingExpectationException``. .. note:: This cookbook entry is an adaption of the blog post titled `"Complex argument matching in Mockery" <https://robertbasic.com/blog/complex-argument-matching-in-mockery/>`_, published by Robert Basic on his blog. cookbook/not_calling_the_constructor.rst 0000644 00000004150 15110326463 0014703 0 ustar 00 .. index:: single: Cookbook; Not Calling the Original Constructor Not Calling the Original Constructor ==================================== When creating generated partial test doubles, Mockery mocks out only the method which we specifically told it to. This means that the original constructor of the class we are mocking will be called. In some cases this is not a desired behavior, as the constructor might issue calls to other methods, or other object collaborators, and as such, can create undesired side-effects in the application's environment when running the tests. If this happens, we need to use runtime partial test doubles, as they don't call the original constructor. .. code-block:: php class MyClass { public function __construct() { echo "Original constructor called." . PHP_EOL; // Other side-effects can happen... } } // This will print "Original constructor called." $mock = \Mockery::mock('MyClass[foo]'); A better approach is to use runtime partial doubles: .. code-block:: php class MyClass { public function __construct() { echo "Original constructor called." . PHP_EOL; // Other side-effects can happen... } } // This will not print anything $mock = \Mockery::mock('MyClass')->makePartial(); $mock->shouldReceive('foo'); This is one of the reason why we don't recommend using generated partial test doubles, but if possible, always use the runtime partials. Read more about :ref:`creating-test-doubles-partial-test-doubles`. .. note:: The way generated partial test doubles work, is a BC break. If you use a really old version of Mockery, it might behave in a way that the constructor is not being called for these generated partials. In the case if you upgrade to a more recent version of Mockery, you'll probably have to change your tests to use runtime partials, instead of generated ones. This change was introduced in early 2013, so it is highly unlikely that you are using a Mockery from before that, so this should not be an issue. getting_started/map.rst.inc 0000644 00000000236 15110326463 0012014 0 ustar 00 * :doc:`/getting_started/installation` * :doc:`/getting_started/upgrading` * :doc:`/getting_started/simple_example` * :doc:`/getting_started/quick_reference` getting_started/index.rst 0000644 00000000234 15110326463 0011574 0 ustar 00 Getting Started =============== .. toctree:: :hidden: installation upgrading simple_example quick_reference .. include:: map.rst.inc getting_started/simple_example.rst 0000644 00000004103 15110326463 0013470 0 ustar 00 .. index:: single: Getting Started; Simple Example Simple Example ============== Imagine we have a ``Temperature`` class which samples the temperature of a locale before reporting an average temperature. The data could come from a web service or any other data source, but we do not have such a class at present. We can, however, assume some basic interactions with such a class based on its interaction with the ``Temperature`` class: .. code-block:: php class Temperature { private $service; public function __construct($service) { $this->service = $service; } public function average() { $total = 0; for ($i=0; $i<3; $i++) { $total += $this->service->readTemp(); } return $total/3; } } Even without an actual service class, we can see how we expect it to operate. When writing a test for the ``Temperature`` class, we can now substitute a mock object for the real service which allows us to test the behaviour of the ``Temperature`` class without actually needing a concrete service instance. .. code-block:: php use \Mockery; class TemperatureTest extends \PHPUnit\Framework\TestCase { public function tearDown() { Mockery::close(); } public function testGetsAverageTemperatureFromThreeServiceReadings() { $service = Mockery::mock('service'); $service->shouldReceive('readTemp') ->times(3) ->andReturn(10, 12, 14); $temperature = new Temperature($service); $this->assertEquals(12, $temperature->average()); } } We create a mock object which our ``Temperature`` class will use and set some expectations for that mock — that it should receive three calls to the ``readTemp`` method, and these calls will return 10, 12, and 14 as results. .. note:: PHPUnit integration can remove the need for a ``tearDown()`` method. See ":doc:`/reference/phpunit_integration`" for more information. getting_started/quick_reference.rst 0000644 00000012020 15110326463 0013613 0 ustar 00 .. index:: single: Quick Reference Quick Reference =============== The purpose of this page is to give a quick and short overview of some of the most common Mockery features. Do read the :doc:`../reference/index` to learn about all the Mockery features. Integrate Mockery with PHPUnit, either by extending the ``MockeryTestCase``: .. code-block:: php use \Mockery\Adapter\Phpunit\MockeryTestCase; class MyTest extends MockeryTestCase { } or by using the ``MockeryPHPUnitIntegration`` trait: .. code-block:: php use \PHPUnit\Framework\TestCase; use \Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; class MyTest extends TestCase { use MockeryPHPUnitIntegration; } Creating a test double: .. code-block:: php $testDouble = \Mockery::mock('MyClass'); Creating a test double that implements a certain interface: .. code-block:: php $testDouble = \Mockery::mock('MyClass, MyInterface'); Expecting a method to be called on a test double: .. code-block:: php $testDouble = \Mockery::mock('MyClass'); $testDouble->shouldReceive('foo'); Expecting a method to **not** be called on a test double: .. code-block:: php $testDouble = \Mockery::mock('MyClass'); $testDouble->shouldNotReceive('foo'); Expecting a method to be called on a test double, once, with a certain argument, and to return a value: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo') ->once() ->with($arg) ->andReturn($returnValue); Expecting a method to be called on a test double and to return a different value for each successive call: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo') ->andReturn(1, 2, 3); $mock->foo(); // int(1); $mock->foo(); // int(2); $mock->foo(); // int(3); $mock->foo(); // int(3); Creating a runtime partial test double: .. code-block:: php $mock = \Mockery::mock('MyClass')->makePartial(); Creating a spy: .. code-block:: php $spy = \Mockery::spy('MyClass'); Expecting that a spy should have received a method call: .. code-block:: php $spy = \Mockery::spy('MyClass'); $spy->foo(); $spy->shouldHaveReceived()->foo(); Not so simple examples ^^^^^^^^^^^^^^^^^^^^^^ Creating a mock object to return a sequence of values from a set of method calls: .. code-block:: php use \Mockery\Adapter\Phpunit\MockeryTestCase; class SimpleTest extends MockeryTestCase { public function testSimpleMock() { $mock = \Mockery::mock(array('pi' => 3.1416, 'e' => 2.71)); $this->assertEquals(3.1416, $mock->pi()); $this->assertEquals(2.71, $mock->e()); } } Creating a mock object which returns a self-chaining Undefined object for a method call: .. code-block:: php use \Mockery\Adapter\Phpunit\MockeryTestCase; class UndefinedTest extends MockeryTestCase { public function testUndefinedValues() { $mock = \Mockery::mock('mymock'); $mock->shouldReceive('divideBy')->with(0)->andReturnUndefined(); $this->assertTrue($mock->divideBy(0) instanceof \Mockery\Undefined); } } Creating a mock object with multiple query calls and a single update call: .. code-block:: php use \Mockery\Adapter\Phpunit\MockeryTestCase; class DbTest extends MockeryTestCase { public function testDbAdapter() { $mock = \Mockery::mock('db'); $mock->shouldReceive('query')->andReturn(1, 2, 3); $mock->shouldReceive('update')->with(5)->andReturn(NULL)->once(); // ... test code here using the mock } } Expecting all queries to be executed before any updates: .. code-block:: php use \Mockery\Adapter\Phpunit\MockeryTestCase; class DbTest extends MockeryTestCase { public function testQueryAndUpdateOrder() { $mock = \Mockery::mock('db'); $mock->shouldReceive('query')->andReturn(1, 2, 3)->ordered(); $mock->shouldReceive('update')->andReturn(NULL)->once()->ordered(); // ... test code here using the mock } } Creating a mock object where all queries occur after startup, but before finish, and where queries are expected with several different params: .. code-block:: php use \Mockery\Adapter\Phpunit\MockeryTestCase; class DbTest extends MockeryTestCase { public function testOrderedQueries() { $db = \Mockery::mock('db'); $db->shouldReceive('startup')->once()->ordered(); $db->shouldReceive('query')->with('CPWR')->andReturn(12.3)->once()->ordered('queries'); $db->shouldReceive('query')->with('MSFT')->andReturn(10.0)->once()->ordered('queries'); $db->shouldReceive('query')->with(\Mockery::pattern("/^....$/"))->andReturn(3.3)->atLeast()->once()->ordered('queries'); $db->shouldReceive('finish')->once()->ordered(); // ... test code here using the mock } } getting_started/installation.rst 0000644 00000002642 15110326463 0013173 0 ustar 00 .. index:: single: Installation Installation ============ Mockery can be installed using Composer or by cloning it from its GitHub repository. These two options are outlined below. Composer -------- You can read more about Composer on `getcomposer.org <https://getcomposer.org>`_. To install Mockery using Composer, first install Composer for your project using the instructions on the `Composer download page <https://getcomposer.org/download/>`_. You can then define your development dependency on Mockery using the suggested parameters below. While every effort is made to keep the master branch stable, you may prefer to use the current stable version tag instead (use the ``@stable`` tag). .. code-block:: json { "require-dev": { "mockery/mockery": "dev-master" } } To install, you then may call: .. code-block:: bash php composer.phar update This will install Mockery as a development dependency, meaning it won't be installed when using ``php composer.phar update --no-dev`` in production. Other way to install is directly from composer command line, as below. .. code-block:: bash php composer.phar require --dev mockery/mockery Git --- The Git repository hosts the development version in its master branch. You can install this using Composer by referencing ``dev-master`` as your preferred version in your project's ``composer.json`` file as the earlier example shows. getting_started/upgrading.rst 0000644 00000005647 15110326463 0012462 0 ustar 00 .. index:: single: Upgrading Upgrading ========= Upgrading to 1.0.0 ------------------ Minimum PHP version +++++++++++++++++++ As of Mockery 1.0.0 the minimum PHP version required is 5.6. Using Mockery with PHPUnit ++++++++++++++++++++++++++ In the "old days", 0.9.x and older, the way Mockery was integrated with PHPUnit was through a PHPUnit listener. That listener would in turn call the ``\Mockery::close()`` method for us. As of 1.0.0, PHPUnit test cases where we want to use Mockery, should either use the ``\Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration`` trait, or extend the ``\Mockery\Adapter\Phpunit\MockeryTestCase`` test case. This will in turn call the ``\Mockery::close()`` method for us. Read the documentation for a detailed overview of ":doc:`/reference/phpunit_integration`". ``\Mockery\Matcher\MustBe`` is deprecated +++++++++++++++++++++++++++++++++++++++++ As of 1.0.0 the ``\Mockery\Matcher\MustBe`` matcher is deprecated and will be removed in Mockery 2.0.0. We recommend instead to use the PHPUnit equivalents of the MustBe matcher. ``allows`` and ``expects`` ++++++++++++++++++++++++++ As of 1.0.0, Mockery has two new methods to set up expectations: ``allows`` and ``expects``. This means that these methods names are now "reserved" for Mockery, or in other words classes you want to mock with Mockery, can't have methods called ``allows`` or ``expects``. Read more in the documentation about this ":doc:`/reference/alternative_should_receive_syntax`". No more implicit regex matching for string arguments ++++++++++++++++++++++++++++++++++++++++++++++++++++ When setting up string arguments in method expectations, Mockery 0.9.x and older, would try to match arguments using a regular expression in a "last attempt" scenario. As of 1.0.0, Mockery will no longer attempt to do this regex matching, but will only try first the identical operator ``===``, and failing that, the equals operator ``==``. If you want to match an argument using regular expressions, please use the new ``\Mockery\Matcher\Pattern`` matcher. Read more in the documentation about this pattern matcher in the ":doc:`/reference/argument_validation`" section. ``andThrow`` ``\Throwable`` +++++++++++++++++++++++++++ As of 1.0.0, the ``andThrow`` can now throw any ``\Throwable``. Upgrading to 0.9 ---------------- The generator was completely rewritten, so any code with a deep integration to mockery will need evaluating. Upgrading to 0.8 ---------------- Since the release of 0.8.0 the following behaviours were altered: 1. The ``shouldIgnoreMissing()`` behaviour optionally applied to mock objects returned an instance of ``\Mockery\Undefined`` when methods called did not match a known expectation. Since 0.8.0, this behaviour was switched to returning ``null`` instead. You can restore the 0.7.2 behaviour by using the following: .. code-block:: php $mock = \Mockery::mock('stdClass')->shouldIgnoreMissing()->asUndefined(); index.rst 0000644 00000003672 15110326463 0006416 0 ustar 00 Mockery ======= Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL). Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library, Mockery is easy to integrate with PHPUnit and can operate alongside phpunit-mock-objects without the World ending. Mock Objects ------------ In unit tests, mock objects simulate the behaviour of real objects. They are commonly utilised to offer test isolation, to stand in for objects which do not yet exist, or to allow for the exploratory design of class APIs without requiring actual implementation up front. The benefits of a mock object framework are to allow for the flexible generation of such mock objects (and stubs). They allow the setting of expected method calls and return values using a flexible API which is capable of capturing every possible real object behaviour in way that is stated as close as possible to a natural language description. Getting Started --------------- Ready to dive into the Mockery framework? Then you can get started by reading the "Getting Started" section! .. toctree:: :hidden: getting_started/index .. include:: getting_started/map.rst.inc Reference --------- The reference contains a complete overview of all features of the Mockery framework. .. toctree:: :hidden: reference/index .. include:: reference/map.rst.inc Mockery ------- Learn about Mockery's configuration, reserved method names, exceptions... .. toctree:: :hidden: mockery/index .. include:: mockery/map.rst.inc Cookbook -------- Want to learn some easy tips and tricks? Take a look at the cookbook articles! .. toctree:: :hidden: cookbook/index .. include:: cookbook/map.rst.inc mockery/map.rst.inc 0000644 00000000177 15110326463 0010302 0 ustar 00 * :doc:`/mockery/configuration` * :doc:`/mockery/exceptions` * :doc:`/mockery/reserved_method_names` * :doc:`/mockery/gotchas` mockery/configuration.rst 0000644 00000007636 15110326463 0011633 0 ustar 00 .. index:: single: Mockery; Configuration Mockery Global Configuration ============================ To allow for a degree of fine-tuning, Mockery utilises a singleton configuration object to store a small subset of core behaviours. The three currently present include: * Option to allow/disallow the mocking of methods which do not actually exist fulfilled (i.e. unused) * Setter/Getter for added a parameter map for internal PHP class methods (``Reflection`` cannot detect these automatically) * Option to drive if quick definitions should define a stub or a mock with an 'at least once' expectation. By default, the first behaviour is enabled. Of course, there are situations where this can lead to unintended consequences. The mocking of non-existent methods may allow mocks based on real classes/objects to fall out of sync with the actual implementations, especially when some degree of integration testing (testing of object wiring) is not being performed. You may allow or disallow this behaviour (whether for whole test suites or just select tests) by using the following call: .. code-block:: php \Mockery::getConfiguration()->allowMockingNonExistentMethods(bool); Passing a true allows the behaviour, false disallows it. It takes effect immediately until switched back. If the behaviour is detected when not allowed, it will result in an Exception being thrown at that point. Note that disallowing this behaviour should be carefully considered since it necessarily removes at least some of Mockery's flexibility. The other two methods are: .. code-block:: php \Mockery::getConfiguration()->setInternalClassMethodParamMap($class, $method, array $paramMap) \Mockery::getConfiguration()->getInternalClassMethodParamMap($class, $method) These are used to define parameters (i.e. the signature string of each) for the methods of internal PHP classes (e.g. SPL, or PECL extension classes like ext/mongo's MongoCollection. Reflection cannot analyse the parameters of internal classes. Most of the time, you never need to do this. It's mainly needed where an internal class method uses pass-by-reference for a parameter - you MUST in such cases ensure the parameter signature includes the ``&`` symbol correctly as Mockery won't correctly add it automatically for internal classes. Note that internal class parameter overriding is not available in PHP 8. This is because incompatible signatures have been reclassified as fatal errors. Finally there is the possibility to change what a quick definition produces. By default quick definitions create stubs but you can change this behaviour by asking Mockery to use 'at least once' expectations. .. code-block:: php \Mockery::getConfiguration()->getQuickDefinitions()->shouldBeCalledAtLeastOnce(bool) Passing a true allows the behaviour, false disallows it. It takes effect immediately until switched back. By doing so you can avoid the proliferating of quick definitions that accumulate overtime in your code since the test would fail in case the 'at least once' expectation is not fulfilled. Disabling reflection caching ---------------------------- Mockery heavily uses `"reflection" <https://secure.php.net/manual/en/book.reflection.php>`_ to do it's job. To speed up things, Mockery caches internally the information it gathers via reflection. In some cases, this caching can cause problems. The **only** known situation when this occurs is when PHPUnit's ``--static-backup`` option is used. If you use ``--static-backup`` and you get an error that looks like the following: .. code-block:: php Error: Internal error: Failed to retrieve the reflection object We suggest turning off the reflection cache as so: .. code-block:: php \Mockery::getConfiguration()->disableReflectionCache(); Turning it back on can be done like so: .. code-block:: php \Mockery::getConfiguration()->enableReflectionCache(); In no other situation should you be required turn this reflection cache off. mockery/index.rst 0000644 00000000215 15110326463 0010055 0 ustar 00 Mockery ======= .. toctree:: :hidden: configuration exceptions reserved_method_names gotchas .. include:: map.rst.inc mockery/reserved_method_names.rst 0000644 00000002125 15110326463 0013312 0 ustar 00 .. index:: single: Reserved Method Names Reserved Method Names ===================== As you may have noticed, Mockery uses a number of methods called directly on all mock objects, for example ``shouldReceive()``. Such methods are necessary in order to setup expectations on the given mock, and so they cannot be implemented on the classes or objects being mocked without creating a method name collision (reported as a PHP fatal error). The methods reserved by Mockery are: * ``shouldReceive()`` * ``shouldNotReceive()`` * ``allows()`` * ``expects()`` * ``shouldAllowMockingMethod()`` * ``shouldIgnoreMissing()`` * ``asUndefined()`` * ``shouldAllowMockingProtectedMethods()`` * ``makePartial()`` * ``byDefault()`` * ``shouldHaveReceived()`` * ``shouldHaveBeenCalled()`` * ``shouldNotHaveReceived()`` * ``shouldNotHaveBeenCalled()`` In addition, all mocks utilise a set of added methods and protected properties which cannot exist on the class or object being mocked. These are far less likely to cause collisions. All properties are prefixed with ``_mockery`` and all method names with ``mockery_``. mockery/gotchas.rst 0000644 00000004637 15110326463 0010412 0 ustar 00 .. index:: single: Mockery; Gotchas Gotchas! ======== Mocking objects in PHP has its limitations and gotchas. Some functionality can't be mocked or can't be mocked YET! If you locate such a circumstance, please please (pretty please with sugar on top) create a new issue on GitHub so it can be documented and resolved where possible. Here is a list to note: 1. Classes containing public ``__wakeup()`` methods can be mocked but the mocked ``__wakeup()`` method will perform no actions and cannot have expectations set for it. This is necessary since Mockery must serialize and unserialize objects to avoid some ``__construct()`` insanity and attempting to mock a ``__wakeup()`` method as normal leads to a ``BadMethodCallException`` being thrown. 2. Mockery has two scenarios where real classes are replaced: Instance mocks and alias mocks. Both will generate PHP fatal errors if the real class is loaded, usually via a require or include statement. Only use these two mock types where autoloading is in place and where classes are not explicitly loaded on a per-file basis using ``require()``, ``require_once()``, etc. 3. Internal PHP classes are not entirely capable of being fully analysed using ``Reflection``. For example, ``Reflection`` cannot reveal details of expected parameters to the methods of such internal classes. As a result, there will be problems where a method parameter is defined to accept a value by reference (Mockery cannot detect this condition and will assume a pass by value on scalars and arrays). If references as internal class method parameters are needed, you should use the ``\Mockery\Configuration::setInternalClassMethodParamMap()`` method. Note, however that internal class parameter overriding is not available in PHP 8 since incompatible signatures have been reclassified as fatal errors. 4. Creating a mock implementing a certain interface with incorrect case in the interface name, and then creating a second mock implementing the same interface, but this time with the correct case, will have undefined behavior due to PHP's ``class_exists`` and related functions being case insensitive. Using the ``::class`` keyword in PHP can help you avoid these mistakes. The gotchas noted above are largely down to PHP's architecture and are assumed to be unavoidable. But - if you figure out a solution (or a better one than what may exist), let us know! mockery/exceptions.rst 0000644 00000005157 15110326463 0011141 0 ustar 00 .. index:: single: Mockery; Exceptions Mockery Exceptions ================== Mockery throws three types of exceptions when it cannot verify a mock object. #. ``\Mockery\Exception\InvalidCountException`` #. ``\Mockery\Exception\InvalidOrderException`` #. ``\Mockery\Exception\NoMatchingExpectationException`` You can capture any of these exceptions in a try...catch block to query them for specific information which is also passed along in the exception message but is provided separately from getters should they be useful when logging or reformatting output. \Mockery\Exception\InvalidCountException ---------------------------------------- The exception class is used when a method is called too many (or too few) times and offers the following methods: * ``getMock()`` - return actual mock object * ``getMockName()`` - return the name of the mock object * ``getMethodName()`` - return the name of the method the failing expectation is attached to * ``getExpectedCount()`` - return expected calls * ``getExpectedCountComparative()`` - returns a string, e.g. ``<=`` used to compare to actual count * ``getActualCount()`` - return actual calls made with given argument constraints \Mockery\Exception\InvalidOrderException ---------------------------------------- The exception class is used when a method is called outside the expected order set using the ``ordered()`` and ``globally()`` expectation modifiers. It offers the following methods: * ``getMock()`` - return actual mock object * ``getMockName()`` - return the name of the mock object * ``getMethodName()`` - return the name of the method the failing expectation is attached to * ``getExpectedOrder()`` - returns an integer represented the expected index for which this call was expected * ``getActualOrder()`` - return the actual index at which this method call occurred. \Mockery\Exception\NoMatchingExpectationException ------------------------------------------------- The exception class is used when a method call does not match any known expectation. All expectations are uniquely identified in a mock object by the method name and the list of expected arguments. You can disable this exception and opt for returning NULL from all unexpected method calls by using the earlier mentioned shouldIgnoreMissing() behaviour modifier. This exception class offers the following methods: * ``getMock()`` - return actual mock object * ``getMockName()`` - return the name of the mock object * ``getMethodName()`` - return the name of the method the failing expectation is attached to * ``getActualArguments()`` - return actual arguments used to search for a matching expectation README.md 0000644 00000000124 15110326463 0006021 0 ustar 00 mockery-docs ============ Document for the PHP Mockery framework on readthedocs.org conf.py 0000644 00000020772 15110326463 0006054 0 ustar 00 # -*- coding: utf-8 -*- # # Mockery Docs documentation build configuration file, created by # sphinx-quickstart on Mon Mar 3 14:04:26 2014. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.todo', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'Mockery Docs' copyright = u'Pádraic Brady, Dave Marshall and contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '1.0' # The full version, including alpha/beta/rc tags. release = '1.0-alpha' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a <link> tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'MockeryDocsdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'MockeryDocs.tex', u'Mockery Docs Documentation', u'Pádraic Brady, Dave Marshall, Wouter, Graham Campbell', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'mockerydocs', u'Mockery Docs Documentation', [u'Pádraic Brady, Dave Marshall, Wouter, Graham Campbell'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'MockeryDocs', u'Mockery Docs Documentation', u'Pádraic Brady, Dave Marshall, Wouter, Graham Campbell', 'MockeryDocs', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False #on_rtd is whether we are on readthedocs.org, this line of code grabbed from docs.readthedocs.org on_rtd = os.environ.get('READTHEDOCS', None) == 'True' if not on_rtd: # only import and set the theme if we're building docs locally import sphinx_rtd_theme html_theme = 'sphinx_rtd_theme' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] print sphinx_rtd_theme.get_html_theme_path() # load PhpLexer from sphinx.highlighting import lexers from pygments.lexers.web import PhpLexer # enable highlighting for PHP code not between <?php ... ?> by default lexers['php'] = PhpLexer(startinline=True) lexers['php-annotations'] = PhpLexer(startinline=True) reference/map.rst.inc 0000644 00000001046 15110326463 0010563 0 ustar 00 * :doc:`/reference/creating_test_doubles` * :doc:`/reference/expectations` * :doc:`/reference/argument_validation` * :doc:`/reference/alternative_should_receive_syntax` * :doc:`/reference/spies` * :doc:`/reference/partial_mocks` * :doc:`/reference/protected_methods` * :doc:`/reference/public_properties` * :doc:`/reference/public_static_properties` * :doc:`/reference/pass_by_reference_behaviours` * :doc:`/reference/demeter_chains` * :doc:`/reference/final_methods_classes` * :doc:`/reference/magic_methods` * :doc:`/reference/phpunit_integration` reference/spies.rst 0000644 00000011200 15110326463 0010352 0 ustar 00 .. index:: single: Reference; Spies Spies ===== Spies are a type of test doubles, but they differ from stubs or mocks in that, that the spies record any interaction between the spy and the System Under Test (SUT), and allow us to make assertions against those interactions after the fact. Creating a spy means we don't have to set up expectations for every method call the double might receive during the test, some of which may not be relevant to the current test. A spy allows us to make assertions about the calls we care about for this test only, reducing the chances of over-specification and making our tests more clear. Spies also allow us to follow the more familiar Arrange-Act-Assert or Given-When-Then style within our tests. With mocks, we have to follow a less familiar style, something along the lines of Arrange-Expect-Act-Assert, where we have to tell our mocks what to expect before we act on the SUT, then assert that those expectations were met: .. code-block:: php // arrange $mock = \Mockery::mock('MyDependency'); $sut = new MyClass($mock); // expect $mock->shouldReceive('foo') ->once() ->with('bar'); // act $sut->callFoo(); // assert \Mockery::close(); Spies allow us to skip the expect part and move the assertion to after we have acted on the SUT, usually making our tests more readable: .. code-block:: php // arrange $spy = \Mockery::spy('MyDependency'); $sut = new MyClass($spy); // act $sut->callFoo(); // assert $spy->shouldHaveReceived() ->foo() ->with('bar'); On the other hand, spies are far less restrictive than mocks, meaning tests are usually less precise, as they let us get away with more. This is usually a good thing, they should only be as precise as they need to be, but while spies make our tests more intent-revealing, they do tend to reveal less about the design of the SUT. If we're having to setup lots of expectations for a mock, in lots of different tests, our tests are trying to tell us something - the SUT is doing too much and probably should be refactored. We don't get this with spies, they simply ignore the calls that aren't relevant to them. Another downside to using spies is debugging. When a mock receives a call that it wasn't expecting, it immediately throws an exception (failing fast), giving us a nice stack trace or possibly even invoking our debugger. With spies, we're simply asserting calls were made after the fact, so if the wrong calls were made, we don't have quite the same just in time context we have with the mocks. Finally, if we need to define a return value for our test double, we can't do that with a spy, only with a mock object. .. note:: This documentation page is an adaption of the blog post titled `"Mockery Spies" <https://davedevelopment.co.uk/2014/10/09/mockery-spies.html>`_, published by Dave Marshall on his blog. Dave is the original author of spies in Mockery. Spies Reference --------------- To verify that a method was called on a spy, we use the ``shouldHaveReceived()`` method: .. code-block:: php $spy->shouldHaveReceived('foo'); To verify that a method was **not** called on a spy, we use the ``shouldNotHaveReceived()`` method: .. code-block:: php $spy->shouldNotHaveReceived('foo'); We can also do argument matching with spies: .. code-block:: php $spy->shouldHaveReceived('foo') ->with('bar'); Argument matching is also possible by passing in an array of arguments to match: .. code-block:: php $spy->shouldHaveReceived('foo', ['bar']); Although when verifying a method was not called, the argument matching can only be done by supplying the array of arguments as the 2nd argument to the ``shouldNotHaveReceived()`` method: .. code-block:: php $spy->shouldNotHaveReceived('foo', ['bar']); This is due to Mockery's internals. Finally, when expecting calls that should have been received, we can also verify the number of calls: .. code-block:: php $spy->shouldHaveReceived('foo') ->with('bar') ->twice(); Alternative shouldReceive syntax ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ As of Mockery 1.0.0, we support calling methods as we would call any PHP method, and not as string arguments to Mockery ``should*`` methods. In cases of spies, this only applies to the ``shouldHaveReceived()`` method: .. code-block:: php $spy->shouldHaveReceived() ->foo('bar'); We can set expectation on number of calls as well: .. code-block:: php $spy->shouldHaveReceived() ->foo('bar') ->twice(); Unfortunately, due to limitations we can't support the same syntax for the ``shouldNotHaveReceived()`` method. reference/phpunit_integration.rst 0000644 00000011365 15110326463 0013335 0 ustar 00 .. index:: single: PHPUnit Integration PHPUnit Integration =================== Mockery was designed as a simple-to-use *standalone* mock object framework, so its need for integration with any testing framework is entirely optional. To integrate Mockery, we need to define a ``tearDown()`` method for our tests containing the following (we may use a shorter ``\Mockery`` namespace alias): .. code-block:: php public function tearDown() { \Mockery::close(); } This static call cleans up the Mockery container used by the current test, and run any verification tasks needed for our expectations. For some added brevity when it comes to using Mockery, we can also explicitly use the Mockery namespace with a shorter alias. For example: .. code-block:: php use \Mockery as m; class SimpleTest extends \PHPUnit\Framework\TestCase { public function testSimpleMock() { $mock = m::mock('simplemock'); $mock->shouldReceive('foo')->with(5, m::any())->once()->andReturn(10); $this->assertEquals(10, $mock->foo(5)); } public function tearDown() { m::close(); } } Mockery ships with an autoloader so we don't need to litter our tests with ``require_once()`` calls. To use it, ensure Mockery is on our ``include_path`` and add the following to our test suite's ``Bootstrap.php`` or ``TestHelper.php`` file: .. code-block:: php require_once 'Mockery/Loader.php'; require_once 'Hamcrest/Hamcrest.php'; $loader = new \Mockery\Loader; $loader->register(); If we are using Composer, we can simplify this to including the Composer generated autoloader file: .. code-block:: php require __DIR__ . '/../vendor/autoload.php'; // assuming vendor is one directory up .. caution:: Prior to Hamcrest 1.0.0, the ``Hamcrest.php`` file name had a small "h" (i.e. ``hamcrest.php``). If upgrading Hamcrest to 1.0.0 remember to check the file name is updated for all your projects.) To integrate Mockery into PHPUnit and avoid having to call the close method and have Mockery remove itself from code coverage reports, have your test case extends the ``\Mockery\Adapter\Phpunit\MockeryTestCase``: .. code-block:: php class MyTest extends \Mockery\Adapter\Phpunit\MockeryTestCase { } An alternative is to use the supplied trait: .. code-block:: php class MyTest extends \PHPUnit\Framework\TestCase { use \Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; } Extending ``MockeryTestCase`` or using the ``MockeryPHPUnitIntegration`` trait is **the recommended way** of integrating Mockery with PHPUnit, since Mockery 1.0.0. PHPUnit listener ---------------- Before the 1.0.0 release, Mockery provided a PHPUnit listener that would call ``Mockery::close()`` for us at the end of a test. This has changed significantly since the 1.0.0 version. Now, Mockery provides a PHPUnit listener that makes tests fail if ``Mockery::close()`` has not been called. It can help identify tests where we've forgotten to include the trait or extend the ``MockeryTestCase``. If we are using PHPUnit's XML configuration approach, we can include the following to load the ``TestListener``: .. code-block:: xml <listeners> <listener class="\Mockery\Adapter\Phpunit\TestListener"></listener> </listeners> Make sure Composer's or Mockery's autoloader is present in the bootstrap file or we will need to also define a "file" attribute pointing to the file of the ``TestListener`` class. If we are creating the test suite programmatically we may add the listener like this: .. code-block:: php // Create the suite. $suite = new PHPUnit\Framework\TestSuite(); // Create the listener and add it to the suite. $result = new PHPUnit\Framework\TestResult(); $result->addListener(new \Mockery\Adapter\Phpunit\TestListener()); // Run the tests. $suite->run($result); .. caution:: PHPUnit provides a functionality that allows `tests to run in a separated process <http://phpunit.de/manual/current/en/appendixes.annotations.html#appendixes.annotations.runTestsInSeparateProcesses>`_, to ensure better isolation. Mockery verifies the mocks expectations using the ``Mockery::close()`` method, and provides a PHPUnit listener, that automatically calls this method for us after every test. However, this listener is not called in the right process when using PHPUnit's process isolation, resulting in expectations that might not be respected, but without raising any ``Mockery\Exception``. To avoid this, we cannot rely on the supplied Mockery PHPUnit ``TestListener``, and we need to explicitly call ``Mockery::close``. The easiest solution to include this call in the ``tearDown()`` method, as explained previously. reference/demeter_chains.rst 0000644 00000003147 15110326463 0012214 0 ustar 00 .. index:: single: Mocking; Demeter Chains Mocking Demeter Chains And Fluent Interfaces ============================================ Both of these terms refer to the growing practice of invoking statements similar to: .. code-block:: php $object->foo()->bar()->zebra()->alpha()->selfDestruct(); The long chain of method calls isn't necessarily a bad thing, assuming they each link back to a local object the calling class knows. As a fun example, Mockery's long chains (after the first ``shouldReceive()`` method) all call to the same instance of ``\Mockery\Expectation``. However, sometimes this is not the case and the chain is constantly crossing object boundaries. In either case, mocking such a chain can be a horrible task. To make it easier Mockery supports demeter chain mocking. Essentially, we shortcut through the chain and return a defined value from the final call. For example, let's assume ``selfDestruct()`` returns the string "Ten!" to $object (an instance of ``CaptainsConsole``). Here's how we could mock it. .. code-block:: php $mock = \Mockery::mock('CaptainsConsole'); $mock->shouldReceive('foo->bar->zebra->alpha->selfDestruct')->andReturn('Ten!'); The above expectation can follow any previously seen format or expectation, except that the method name is simply the string of all expected chain calls separated by ``->``. Mockery will automatically setup the chain of expected calls with its final return values, regardless of whatever intermediary object might be used in the real implementation. Arguments to all members of the chain (except the final call) are ignored in this process. reference/instance_mocking.rst 0000644 00000001445 15110326463 0012554 0 ustar 00 .. index:: single: Mocking; Instance Instance Mocking ================ Instance mocking means that a statement like: .. code-block:: php $obj = new \MyNamespace\Foo; ...will actually generate a mock object. This is done by replacing the real class with an instance mock (similar to an alias mock), as with mocking public methods. The alias will import its expectations from the original mock of that type (note that the original is never verified and should be ignored after its expectations are setup). This lets you intercept instantiation where you can't simply inject a replacement object. As before, this does not prevent a require statement from including the real class and triggering a fatal PHP error. It's intended for use where autoloading is the primary class loading mechanism. reference/index.rst 0000644 00000000620 15110326463 0010342 0 ustar 00 Reference ========= .. toctree:: :hidden: creating_test_doubles expectations argument_validation alternative_should_receive_syntax spies partial_mocks protected_methods public_properties public_static_properties pass_by_reference_behaviours demeter_chains final_methods_classes magic_methods phpunit_integration .. include:: map.rst.inc reference/alternative_should_receive_syntax.rst 0000644 00000004515 15110326463 0016246 0 ustar 00 .. index:: single: Alternative shouldReceive Syntax Alternative shouldReceive Syntax ================================ As of Mockery 1.0.0, we support calling methods as we would call any PHP method, and not as string arguments to Mockery ``should*`` methods. The two Mockery methods that enable this are ``allows()`` and ``expects()``. Allows ------ We use ``allows()`` when we create stubs for methods that return a predefined return value, but for these method stubs we don't care how many times, or if at all, were they called. .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->allows([ 'name_of_method_1' => 'return value', 'name_of_method_2' => 'return value', ]); This is equivalent with the following ``shouldReceive`` syntax: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive([ 'name_of_method_1' => 'return value', 'name_of_method_2' => 'return value', ]); Note that with this format, we also tell Mockery that we don't care about the arguments to the stubbed methods. If we do care about the arguments, we would do it like so: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->allows() ->name_of_method_1($arg1) ->andReturn('return value'); This is equivalent with the following ``shouldReceive`` syntax: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method_1') ->with($arg1) ->andReturn('return value'); Expects ------- We use ``expects()`` when we want to verify that a particular method was called: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->expects() ->name_of_method_1($arg1) ->andReturn('return value'); This is equivalent with the following ``shouldReceive`` syntax: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method_1') ->once() ->with($arg1) ->andReturn('return value'); By default ``expects()`` sets up an expectation that the method should be called once and once only. If we expect more than one call to the method, we can change that expectation: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->expects() ->name_of_method_1($arg1) ->twice() ->andReturn('return value'); reference/expectations.rst 0000644 00000037113 15110326463 0011750 0 ustar 00 .. index:: single: Expectations Expectation Declarations ======================== .. note:: In order for our expectations to work we MUST call ``Mockery::close()``, preferably in a callback method such as ``tearDown`` or ``_after`` (depending on whether or not we're integrating Mockery with another framework). This static call cleans up the Mockery container used by the current test, and run any verification tasks needed for our expectations. Once we have created a mock object, we'll often want to start defining how exactly it should behave (and how it should be called). This is where the Mockery expectation declarations take over. Declaring Method Call Expectations ---------------------------------- To tell our test double to expect a call for a method with a given name, we use the ``shouldReceive`` method: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method'); This is the starting expectation upon which all other expectations and constraints are appended. We can declare more than one method call to be expected: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method_1', 'name_of_method_2'); All of these will adopt any chained expectations or constraints. It is possible to declare the expectations for the method calls, along with their return values: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive([ 'name_of_method_1' => 'return value 1', 'name_of_method_2' => 'return value 2', ]); There's also a shorthand way of setting up method call expectations and their return values: .. code-block:: php $mock = \Mockery::mock('MyClass', ['name_of_method_1' => 'return value 1', 'name_of_method_2' => 'return value 2']); All of these will adopt any additional chained expectations or constraints. We can declare that a test double should not expect a call to the given method name: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldNotReceive('name_of_method'); This method is a convenience method for calling ``shouldReceive()->never()``. Declaring Method Argument Expectations -------------------------------------- For every method we declare expectation for, we can add constraints that the defined expectations apply only to the method calls that match the expected argument list: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->with($arg1, $arg2, ...); // or $mock->shouldReceive('name_of_method') ->withArgs([$arg1, $arg2, ...]); We can add a lot more flexibility to argument matching using the built in matcher classes (see later). For example, ``\Mockery::any()`` matches any argument passed to that position in the ``with()`` parameter list. Mockery also allows Hamcrest library matchers - for example, the Hamcrest function ``anything()`` is equivalent to ``\Mockery::any()``. It's important to note that this means all expectations attached only apply to the given method when it is called with these exact arguments: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo')->with('Hello'); $mock->foo('Goodbye'); // throws a NoMatchingExpectationException This allows for setting up differing expectations based on the arguments provided to expected calls. Argument matching with closures ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Instead of providing a built-in matcher for each argument, we can provide a closure that matches all passed arguments at once: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->withArgs(closure); The given closure receives all the arguments passed in the call to the expected method. In this way, this expectation only applies to method calls where passed arguments make the closure evaluate to true: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo')->withArgs(function ($arg) { if ($arg % 2 == 0) { return true; } return false; }); $mock->foo(4); // matches the expectation $mock->foo(3); // throws a NoMatchingExpectationException Argument matching with some of given values ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ We can provide expected arguments that match passed arguments when mocked method is called. .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->withSomeOfArgs(arg1, arg2, arg3, ...); The given expected arguments order doesn't matter. Check if expected values are included or not, but type should be matched: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo') ->withSomeOfArgs(1, 2); $mock->foo(1, 2, 3); // matches the expectation $mock->foo(3, 2, 1); // matches the expectation (passed order doesn't matter) $mock->foo('1', '2'); // throws a NoMatchingExpectationException (type should be matched) $mock->foo(3); // throws a NoMatchingExpectationException Any, or no arguments ^^^^^^^^^^^^^^^^^^^^ We can declare that the expectation matches a method call regardless of what arguments are passed: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->withAnyArgs(); This is set by default unless otherwise specified. We can declare that the expectation matches method calls with zero arguments: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->withNoArgs(); Declaring Return Value Expectations ----------------------------------- For mock objects, we can tell Mockery what return values to return from the expected method calls. For that we can use the ``andReturn()`` method: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->andReturn($value); This sets a value to be returned from the expected method call. It is possible to set up expectation for multiple return values. By providing a sequence of return values, we tell Mockery what value to return on every subsequent call to the method: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->andReturn($value1, $value2, ...) The first call will return ``$value1`` and the second call will return ``$value2``. If we call the method more times than the number of return values we declared, Mockery will return the final value for any subsequent method call: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo')->andReturn(1, 2, 3); $mock->foo(); // int(1) $mock->foo(); // int(2) $mock->foo(); // int(3) $mock->foo(); // int(3) The same can be achieved using the alternative syntax: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->andReturnValues([$value1, $value2, ...]) It accepts a simple array instead of a list of parameters. The order of return is determined by the numerical index of the given array with the last array member being returned on all calls once previous return values are exhausted. The following two options are primarily for communication with test readers: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->andReturnNull(); // or $mock->shouldReceive('name_of_method') ->andReturn([null]); They mark the mock object method call as returning ``null`` or nothing. Sometimes we want to calculate the return results of the method calls, based on the arguments passed to the method. We can do that with the ``andReturnUsing()`` method which accepts one or more closure: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->andReturnUsing(closure, ...); Closures can be queued by passing them as extra parameters as for ``andReturn()``. Occasionally, it can be useful to echo back one of the arguments that a method is called with. In this case we can use the ``andReturnArg()`` method; the argument to be returned is specified by its index in the arguments list: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->andReturnArg(1); This returns the second argument (index #1) from the list of arguments when the method is called. .. note:: We cannot currently mix ``andReturnUsing()`` or ``andReturnArg`` with ``andReturn()``. If we are mocking fluid interfaces, the following method will be helpful: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->andReturnSelf(); It sets the return value to the mocked class name. Throwing Exceptions ------------------- We can tell the method of mock objects to throw exceptions: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->andThrow(new Exception); It will throw the given ``Exception`` object when called. Rather than an object, we can pass in the ``Exception`` class, message and/or code to use when throwing an ``Exception`` from the mocked method: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->andThrow('exception_name', 'message', 123456789); .. _expectations-setting-public-properties: Setting Public Properties ------------------------- Used with an expectation so that when a matching method is called, we can cause a mock object's public property to be set to a specified value, by using ``andSet()`` or ``set()``: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->andSet($property, $value); // or $mock->shouldReceive('name_of_method') ->set($property, $value); In cases where we want to call the real method of the class that was mocked and return its result, the ``passthru()`` method tells the expectation to bypass a return queue: .. code-block:: php passthru() It allows expectation matching and call count validation to be applied against real methods while still calling the real class method with the expected arguments. Declaring Call Count Expectations --------------------------------- Besides setting expectations on the arguments of the method calls, and the return values of those same calls, we can set expectations on how many times should any method be called. When a call count expectation is not met, a ``\Mockery\Expectation\InvalidCountException`` will be thrown. .. note:: It is absolutely required to call ``\Mockery::close()`` at the end of our tests, for example in the ``tearDown()`` method of PHPUnit. Otherwise Mockery will not verify the calls made against our mock objects. We can declare that the expected method may be called zero or more times: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->zeroOrMoreTimes(); This is the default for all methods unless otherwise set. To tell Mockery to expect an exact number of calls to a method, we can use the following: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->times($n); where ``$n`` is the number of times the method should be called. A couple of most common cases got their shorthand methods. To declare that the expected method must be called one time only: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->once(); To declare that the expected method must be called two times: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->twice(); To declare that the expected method must never be called: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->never(); Call count modifiers ^^^^^^^^^^^^^^^^^^^^ The call count expectations can have modifiers set. If we want to tell Mockery the minimum number of times a method should be called, we use ``atLeast()``: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->atLeast() ->times(3); ``atLeast()->times(3)`` means the call must be called at least three times (given matching method args) but never less than three times. Similarly, we can tell Mockery the maximum number of times a method should be called, using ``atMost()``: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->atMost() ->times(3); ``atMost()->times(3)`` means the call must be called no more than three times. If the method gets no calls at all, the expectation will still be met. We can also set a range of call counts, using ``between()``: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('name_of_method') ->between($min, $max); This is actually identical to using ``atLeast()->times($min)->atMost()->times($max)`` but is provided as a shorthand. It may be followed by a ``times()`` call with no parameter to preserve the APIs natural language readability. Multiple Calls with Different Expectations ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If a method is expected to get called multiple times with different arguments and/or return values we can simply repeat the expectations. The same of course also works if we expect multiple calls to different methods. .. code-block:: php $mock = \Mockery::mock('MyClass'); // Expectations for the 1st call $mock->shouldReceive('name_of_method'); ->once() ->with('arg1') ->andReturn($value1) // 2nd call to same method ->shouldReceive('name_of_method') ->once() ->with('arg2') ->andReturn($value2) // final call to another method ->shouldReceive('other_method') ->once() ->with('other') ->andReturn($value_other); Expectation Declaration Utilities --------------------------------- Declares that this method is expected to be called in a specific order in relation to similarly marked methods. .. code-block:: php ordered() The order is dictated by the order in which this modifier is actually used when setting up mocks. Declares the method as belonging to an order group (which can be named or numbered). Methods within a group can be called in any order, but the ordered calls from outside the group are ordered in relation to the group: .. code-block:: php ordered(group) We can set up so that method1 is called before group1 which is in turn called before method2. When called prior to ``ordered()`` or ``ordered(group)``, it declares this ordering to apply across all mock objects (not just the current mock): .. code-block:: php globally() This allows for dictating order expectations across multiple mocks. The ``byDefault()`` marks an expectation as a default. Default expectations are applied unless a non-default expectation is created: .. code-block:: php byDefault() These later expectations immediately replace the previously defined default. This is useful so we can setup default mocks in our unit test ``setup()`` and later tweak them in specific tests as needed. Returns the current mock object from an expectation chain: .. code-block:: php getMock() Useful where we prefer to keep mock setups as a single statement, e.g.: .. code-block:: php $mock = \Mockery::mock('foo')->shouldReceive('foo')->andReturn(1)->getMock(); reference/public_static_properties.rst 0000644 00000001275 15110326463 0014343 0 ustar 00 .. index:: single: Mocking; Public Static Methods Mocking Public Static Methods ============================= Static methods are not called on real objects, so normal mock objects can't mock them. Mockery supports class aliased mocks, mocks representing a class name which would normally be loaded (via autoloading or a require statement) in the system under test. These aliases block that loading (unless via a require statement - so please use autoloading!) and allow Mockery to intercept static method calls and add expectations for them. See the :ref:`creating-test-doubles-aliasing` section for more information on creating aliased mocks, for the purpose of mocking public static methods. reference/protected_methods.rst 0000644 00000001234 15110326463 0012751 0 ustar 00 .. index:: single: Mocking; Protected Methods Mocking Protected Methods ========================= By default, Mockery does not allow mocking protected methods. We do not recommend mocking protected methods, but there are cases when there is no other solution. For those cases we have the ``shouldAllowMockingProtectedMethods()`` method. It instructs Mockery to specifically allow mocking of protected methods, for that one class only: .. code-block:: php class MyClass { protected function foo() { } } $mock = \Mockery::mock('MyClass') ->shouldAllowMockingProtectedMethods(); $mock->shouldReceive('foo'); reference/partial_mocks.rst 0000644 00000010276 15110326463 0012073 0 ustar 00 .. index:: single: Mocking; Partial Mocks Creating Partial Mocks ====================== Partial mocks are useful when we only need to mock several methods of an object leaving the remainder free to respond to calls normally (i.e. as implemented). Mockery implements three distinct strategies for creating partials. Each has specific advantages and disadvantages so which strategy we use will depend on our own preferences and the source code in need of mocking. We have previously talked a bit about :ref:`creating-test-doubles-partial-test-doubles`, but we'd like to expand on the subject a bit here. #. Runtime partial test doubles #. Generated partial test doubles #. Proxied Partial Mock Runtime partial test doubles ---------------------------- A runtime partial test double, also known as a passive partial mock, is a kind of a default state of being for a mocked object. .. code-block:: php $mock = \Mockery::mock('MyClass')->makePartial(); With a runtime partial, we assume that all methods will simply defer to the parent class (``MyClass``) original methods unless a method call matches a known expectation. If we have no matching expectation for a specific method call, that call is deferred to the class being mocked. Since the division between mocked and unmocked calls depends entirely on the expectations we define, there is no need to define which methods to mock in advance. See the cookbook entry on :doc:`../cookbook/big_parent_class` for an example usage of runtime partial test doubles. Generated Partial Test Doubles ------------------------------ A generated partial test double, also known as a traditional partial mock, defines ahead of time which methods of a class are to be mocked and which are to be left unmocked (i.e. callable as normal). The syntax for creating traditional mocks is: .. code-block:: php $mock = \Mockery::mock('MyClass[foo,bar]'); In the above example, the ``foo()`` and ``bar()`` methods of MyClass will be mocked but no other MyClass methods are touched. We will need to define expectations for the ``foo()`` and ``bar()`` methods to dictate their mocked behaviour. Don't forget that we can pass in constructor arguments since unmocked methods may rely on those! .. code-block:: php $mock = \Mockery::mock('MyNamespace\MyClass[foo]', array($arg1, $arg2)); See the :ref:`creating-test-doubles-constructor-arguments` section to read up on them. .. note:: Even though we support generated partial test doubles, we do not recommend using them. Proxied Partial Mock -------------------- A proxied partial mock is a partial of last resort. We may encounter a class which is simply not capable of being mocked because it has been marked as final. Similarly, we may find a class with methods marked as final. In such a scenario, we cannot simply extend the class and override methods to mock - we need to get creative. .. code-block:: php $mock = \Mockery::mock(new MyClass); Yes, the new mock is a Proxy. It intercepts calls and reroutes them to the proxied object (which we construct and pass in) for methods which are not subject to any expectations. Indirectly, this allows us to mock methods marked final since the Proxy is not subject to those limitations. The tradeoff should be obvious - a proxied partial will fail any typehint checks for the class being mocked since it cannot extend that class. Special Internal Cases ---------------------- All mock objects, with the exception of Proxied Partials, allows us to make any expectation call to the underlying real class method using the ``passthru()`` expectation call. This will return values from the real call and bypass any mocked return queue (which can simply be omitted obviously). There is a fourth kind of partial mock reserved for internal use. This is automatically generated when we attempt to mock a class containing methods marked final. Since we cannot override such methods, they are simply left unmocked. Typically, we don't need to worry about this but if we really really must mock a final method, the only possible means is through a Proxied Partial Mock. SplFileInfo, for example, is a common class subject to this form of automatic internal partial since it contains public final methods used internally. reference/magic_methods.rst 0000644 00000001257 15110326463 0012045 0 ustar 00 .. index:: single: Mocking; Magic Methods PHP Magic Methods ================= PHP magic methods which are prefixed with a double underscore, e.g. ``__set()``, pose a particular problem in mocking and unit testing in general. It is strongly recommended that unit tests and mock objects do not directly refer to magic methods. Instead, refer only to the virtual methods and properties these magic methods simulate. Following this piece of advice will ensure we are testing the real API of classes and also ensures there is no conflict should Mockery override these magic methods, which it will inevitably do in order to support its role in intercepting method calls and properties. reference/final_methods_classes.rst 0000644 00000002507 15110326463 0013572 0 ustar 00 .. index:: single: Mocking; Final Classes/Methods Dealing with Final Classes/Methods ================================== One of the primary restrictions of mock objects in PHP, is that mocking classes or methods marked final is hard. The final keyword prevents methods so marked from being replaced in subclasses (subclassing is how mock objects can inherit the type of the class or object being mocked). The simplest solution is to implement an interface in your final class and typehint against / mock this. However this may not be possible in some third party libraries. Mockery does allow creating "proxy mocks" from classes marked final, or from classes with methods marked final. This offers all the usual mock object goodness but the resulting mock will not inherit the class type of the object being mocked, i.e. it will not pass any instanceof comparison. Methods marked as final will be proxied to the original method, i.e., final methods can't be mocked. We can create a proxy mock by passing the instantiated object we wish to mock into ``\Mockery::mock()``, i.e. Mockery will then generate a Proxy to the real object and selectively intercept method calls for the purposes of setting and meeting expectations. See the :ref:`creating-test-doubles-partial-test-doubles` chapter, the subsection about proxied partial test doubles. reference/public_properties.rst 0000644 00000001465 15110326463 0012775 0 ustar 00 .. index:: single: Mocking; Public Properties Mocking Public Properties ========================= Mockery allows us to mock properties in several ways. One way is that we can set a public property and its value on any mock object. The second is that we can use the expectation methods ``set()`` and ``andSet()`` to set property values if that expectation is ever met. You can read more about :ref:`expectations-setting-public-properties`. .. note:: In general, Mockery does not support mocking any magic methods since these are generally not considered a public API (and besides it is a bit difficult to differentiate them when you badly need them for mocking!). So please mock virtual properties (those relying on ``__get()`` and ``__set()``) as if they were actually declared on the class. reference/pass_by_reference_behaviours.rst 0000644 00000010342 15110326463 0015142 0 ustar 00 .. index:: single: Pass-By-Reference Method Parameter Behaviour Preserving Pass-By-Reference Method Parameter Behaviour ======================================================= PHP Class method may accept parameters by reference. In this case, changes made to the parameter (a reference to the original variable passed to the method) are reflected in the original variable. An example: .. code-block:: php class Foo { public function bar(&$a) { $a++; } } $baz = 1; $foo = new Foo; $foo->bar($baz); echo $baz; // will echo the integer 2 In the example above, the variable ``$baz`` is passed by reference to ``Foo::bar()`` (notice the ``&`` symbol in front of the parameter?). Any change ``bar()`` makes to the parameter reference is reflected in the original variable, ``$baz``. Mockery handles references correctly for all methods where it can analyse the parameter (using ``Reflection``) to see if it is passed by reference. To mock how a reference is manipulated by the class method, we can use a closure argument matcher to manipulate it, i.e. ``\Mockery::on()`` - see the :ref:`argument-validation-complex-argument-validation` chapter. There is an exception for internal PHP classes where Mockery cannot analyse method parameters using ``Reflection`` (a limitation in PHP). To work around this, we can explicitly declare method parameters for an internal class using ``\Mockery\Configuration::setInternalClassMethodParamMap()``. Here's an example using ``MongoCollection::insert()``. ``MongoCollection`` is an internal class offered by the mongo extension from PECL. Its ``insert()`` method accepts an array of data as the first parameter, and an optional options array as the second parameter. The original data array is updated (i.e. when a ``insert()`` pass-by-reference parameter) to include a new ``_id`` field. We can mock this behaviour using a configured parameter map (to tell Mockery to expect a pass by reference parameter) and a ``Closure`` attached to the expected method parameter to be updated. Here's a PHPUnit unit test verifying that this pass-by-reference behaviour is preserved: .. code-block:: php public function testCanOverrideExpectedParametersOfInternalPHPClassesToPreserveRefs() { \Mockery::getConfiguration()->setInternalClassMethodParamMap( 'MongoCollection', 'insert', array('&$data', '$options = array()') ); $m = \Mockery::mock('MongoCollection'); $m->shouldReceive('insert')->with( \Mockery::on(function(&$data) { if (!is_array($data)) return false; $data['_id'] = 123; return true; }), \Mockery::any() ); $data = array('a'=>1,'b'=>2); $m->insert($data); $this->assertTrue(isset($data['_id'])); $this->assertEquals(123, $data['_id']); \Mockery::resetContainer(); } Protected Methods ----------------- When dealing with protected methods, and trying to preserve pass by reference behavior for them, a different approach is required. .. code-block:: php class Model { public function test(&$data) { return $this->doTest($data); } protected function doTest(&$data) { $data['something'] = 'wrong'; return $this; } } class Test extends \PHPUnit\Framework\TestCase { public function testModel() { $mock = \Mockery::mock('Model[test]')->shouldAllowMockingProtectedMethods(); $mock->shouldReceive('test') ->with(\Mockery::on(function(&$data) { $data['something'] = 'wrong'; return true; })); $data = array('foo' => 'bar'); $mock->test($data); $this->assertTrue(isset($data['something'])); $this->assertEquals('wrong', $data['something']); } } This is quite an edge case, so we need to change the original code a little bit, by creating a public method that will call our protected method, and then mock that, instead of the protected method. This new public method will act as a proxy to our protected method. reference/creating_test_doubles.rst 0000644 00000034176 15110326463 0013620 0 ustar 00 .. index:: single: Reference; Creating Test Doubles Creating Test Doubles ===================== Mockery's main goal is to help us create test doubles. It can create stubs, mocks, and spies. Stubs and mocks are created the same. The difference between the two is that a stub only returns a preset result when called, while a mock needs to have expectations set on the method calls it expects to receive. Spies are a type of test doubles that keep track of the calls they received, and allow us to inspect these calls after the fact. When creating a test double object, we can pass in an identifier as a name for our test double. If we pass it no identifier, the test double name will be unknown. Furthermore, the identifier does not have to be a class name. It is a good practice, and our recommendation, to always name the test doubles with the same name as the underlying class we are creating test doubles for. If the identifier we use for our test double is a name of an existing class, the test double will inherit the type of the class (via inheritance), i.e. the mock object will pass type hints or ``instanceof`` evaluations for the existing class. This is useful when a test double must be of a specific type, to satisfy the expectations our code has. Stubs and mocks --------------- Stubs and mocks are created by calling the ``\Mockery::mock()`` method. The following example shows how to create a stub, or a mock, object named "foo": .. code-block:: php $mock = \Mockery::mock('foo'); The mock object created like this is the loosest form of mocks possible, and is an instance of ``\Mockery\MockInterface``. .. note:: All test doubles created with Mockery are an instance of ``\Mockery\MockInterface``, regardless are they a stub, mock or a spy. To create a stub or a mock object with no name, we can call the ``mock()`` method with no parameters: .. code-block:: php $mock = \Mockery::mock(); As we stated earlier, we don't recommend creating stub or mock objects without a name. Classes, abstracts, interfaces ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The recommended way to create a stub or a mock object is by using a name of an existing class we want to create a test double of: .. code-block:: php $mock = \Mockery::mock('MyClass'); This stub or mock object will have the type of ``MyClass``, through inheritance. Stub or mock objects can be based on any concrete class, abstract class or even an interface. The primary purpose is to ensure the mock object inherits a specific type for type hinting. .. code-block:: php $mock = \Mockery::mock('MyInterface'); This stub or mock object will implement the ``MyInterface`` interface. .. note:: Classes marked final, or classes that have methods marked final cannot be mocked fully. Mockery supports creating partial mocks for these cases. Partial mocks will be explained later in the documentation. Mockery also supports creating stub or mock objects based on a single existing class, which must implement one or more interfaces. We can do this by providing a comma-separated list of the class and interfaces as the first argument to the ``\Mockery::mock()`` method: .. code-block:: php $mock = \Mockery::mock('MyClass, MyInterface, OtherInterface'); This stub or mock object will now be of type ``MyClass`` and implement the ``MyInterface`` and ``OtherInterface`` interfaces. .. note:: The class name doesn't need to be the first member of the list but it's a friendly convention to use for readability. We can tell a mock to implement the desired interfaces by passing the list of interfaces as the second argument: .. code-block:: php $mock = \Mockery::mock('MyClass', 'MyInterface, OtherInterface'); For all intents and purposes, this is the same as the previous example. Spies ----- The third type of test doubles Mockery supports are spies. The main difference between spies and mock objects is that with spies we verify the calls made against our test double after the calls were made. We would use a spy when we don't necessarily care about all of the calls that are going to be made to an object. A spy will return ``null`` for all method calls it receives. It is not possible to tell a spy what will be the return value of a method call. If we do that, then we would deal with a mock object, and not with a spy. We create a spy by calling the ``\Mockery::spy()`` method: .. code-block:: php $spy = \Mockery::spy('MyClass'); Just as with stubs or mocks, we can tell Mockery to base a spy on any concrete or abstract class, or to implement any number of interfaces: .. code-block:: php $spy = \Mockery::spy('MyClass, MyInterface, OtherInterface'); This spy will now be of type ``MyClass`` and implement the ``MyInterface`` and ``OtherInterface`` interfaces. .. note:: The ``\Mockery::spy()`` method call is actually a shorthand for calling ``\Mockery::mock()->shouldIgnoreMissing()``. The ``shouldIgnoreMissing`` method is a "behaviour modifier". We'll discuss them a bit later. Mocks vs. Spies --------------- Let's try and illustrate the difference between mocks and spies with the following example: .. code-block:: php $mock = \Mockery::mock('MyClass'); $spy = \Mockery::spy('MyClass'); $mock->shouldReceive('foo')->andReturn(42); $mockResult = $mock->foo(); $spyResult = $spy->foo(); $spy->shouldHaveReceived()->foo(); var_dump($mockResult); // int(42) var_dump($spyResult); // null As we can see from this example, with a mock object we set the call expectations before the call itself, and we get the return result we expect it to return. With a spy object on the other hand, we verify the call has happened after the fact. The return result of a method call against a spy is always ``null``. We also have a dedicated chapter to :doc:`spies` only. .. _creating-test-doubles-partial-test-doubles: Partial Test Doubles -------------------- Partial doubles are useful when we want to stub out, set expectations for, or spy on *some* methods of a class, but run the actual code for other methods. We differentiate between three types of partial test doubles: * runtime partial test doubles, * generated partial test doubles, and * proxied partial test doubles. Runtime partial test doubles ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ What we call a runtime partial, involves creating a test double and then telling it to make itself partial. Any method calls that the double hasn't been told to allow or expect, will act as they would on a normal instance of the object. .. code-block:: php class Foo { function foo() { return 123; } function bar() { return $this->foo(); } } $foo = mock(Foo::class)->makePartial(); $foo->foo(); // int(123); We can then tell the test double to allow or expect calls as with any other Mockery double. .. code-block:: php $foo->shouldReceive('foo')->andReturn(456); $foo->bar(); // int(456) See the cookbook entry on :doc:`../cookbook/big_parent_class` for an example usage of runtime partial test doubles. Generated partial test doubles ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The second type of partial double we can create is what we call a generated partial. With generated partials, we specifically tell Mockery which methods we want to be able to allow or expect calls to. All other methods will run the actual code *directly*, so stubs and expectations on these methods will not work. .. code-block:: php class Foo { function foo() { return 123; } function bar() { return $this->foo(); } } $foo = mock("Foo[foo]"); $foo->foo(); // error, no expectation set $foo->shouldReceive('foo')->andReturn(456); $foo->foo(); // int(456) // setting an expectation for this has no effect $foo->shouldReceive('bar')->andReturn(999); $foo->bar(); // int(456) It's also possible to specify explicitly which methods to run directly using the `!method` syntax: .. code-block:: php class Foo { function foo() { return 123; } function bar() { return $this->foo(); } } $foo = mock("Foo[!foo]"); $foo->foo(); // int(123) $foo->bar(); // error, no expectation set .. note:: Even though we support generated partial test doubles, we do not recommend using them. One of the reasons why is because a generated partial will call the original constructor of the mocked class. This can have unwanted side-effects during testing application code. See :doc:`../cookbook/not_calling_the_constructor` for more details. Proxied partial test doubles ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ A proxied partial mock is a partial of last resort. We may encounter a class which is simply not capable of being mocked because it has been marked as final. Similarly, we may find a class with methods marked as final. In such a scenario, we cannot simply extend the class and override methods to mock - we need to get creative. .. code-block:: php $mock = \Mockery::mock(new MyClass); Yes, the new mock is a Proxy. It intercepts calls and reroutes them to the proxied object (which we construct and pass in) for methods which are not subject to any expectations. Indirectly, this allows us to mock methods marked final since the Proxy is not subject to those limitations. The tradeoff should be obvious - a proxied partial will fail any typehint checks for the class being mocked since it cannot extend that class. .. _creating-test-doubles-aliasing: Aliasing -------- Prefixing the valid name of a class (which is NOT currently loaded) with "alias:" will generate an "alias mock". Alias mocks create a class alias with the given classname to stdClass and are generally used to enable the mocking of public static methods. Expectations set on the new mock object which refer to static methods will be used by all static calls to this class. .. code-block:: php $mock = \Mockery::mock('alias:MyClass'); .. note:: Even though aliasing classes is supported, we do not recommend it. Overloading ----------- Prefixing the valid name of a class (which is NOT currently loaded) with "overload:" will generate an alias mock (as with "alias:") except that created new instances of that class will import any expectations set on the origin mock (``$mock``). The origin mock is never verified since it's used an expectation store for new instances. For this purpose we use the term "instance mock" to differentiate it from the simpler "alias mock". In other words, an instance mock will "intercept" when a new instance of the mocked class is created, then the mock will be used instead. This is useful especially when mocking hard dependencies which will be discussed later. .. code-block:: php $mock = \Mockery::mock('overload:MyClass'); .. note:: Using alias/instance mocks across more than one test will generate a fatal error since we can't have two classes of the same name. To avoid this, run each test of this kind in a separate PHP process (which is supported out of the box by both PHPUnit and PHPT). .. _creating-test-doubles-named-mocks: Named Mocks ----------- The ``namedMock()`` method will generate a class called by the first argument, so in this example ``MyClassName``. The rest of the arguments are treated in the same way as the ``mock`` method: .. code-block:: php $mock = \Mockery::namedMock('MyClassName', 'DateTime'); This example would create a class called ``MyClassName`` that extends ``DateTime``. Named mocks are quite an edge case, but they can be useful when code depends on the ``__CLASS__`` magic constant, or when we need two derivatives of an abstract type, that are actually different classes. See the cookbook entry on :doc:`../cookbook/class_constants` for an example usage of named mocks. .. note:: We can only create a named mock once, any subsequent calls to ``namedMock``, with different arguments are likely to cause exceptions. .. _creating-test-doubles-constructor-arguments: Constructor Arguments --------------------- Sometimes the mocked class has required constructor arguments. We can pass these to Mockery as an indexed array, as the 2nd argument: .. code-block:: php $mock = \Mockery::mock('MyClass', [$constructorArg1, $constructorArg2]); or if we need the ``MyClass`` to implement an interface as well, as the 3rd argument: .. code-block:: php $mock = \Mockery::mock('MyClass', 'MyInterface', [$constructorArg1, $constructorArg2]); Mockery now knows to pass in ``$constructorArg1`` and ``$constructorArg2`` as arguments to the constructor. .. _creating-test-doubles-behavior-modifiers: Behavior Modifiers ------------------ When creating a mock object, we may wish to use some commonly preferred behaviours that are not the default in Mockery. The use of the ``shouldIgnoreMissing()`` behaviour modifier will label this mock object as a Passive Mock: .. code-block:: php \Mockery::mock('MyClass')->shouldIgnoreMissing(); In such a mock object, calls to methods which are not covered by expectations will return ``null`` instead of the usual error about there being no expectation matching the call. On PHP >= 7.0.0, methods with missing expectations that have a return type will return either a mock of the object (if return type is a class) or a "falsy" primitive value, e.g. empty string, empty array, zero for ints and floats, false for bools, or empty closures. On PHP >= 7.1.0, methods with missing expectations and nullable return type will return null. We can optionally prefer to return an object of type ``\Mockery\Undefined`` (i.e. a ``null`` object) (which was the 0.7.2 behaviour) by using an additional modifier: .. code-block:: php \Mockery::mock('MyClass')->shouldIgnoreMissing()->asUndefined(); The returned object is nothing more than a placeholder so if, by some act of fate, it's erroneously used somewhere it shouldn't, it will likely not pass a logic check. We have encountered the ``makePartial()`` method before, as it is the method we use to create runtime partial test doubles: .. code-block:: php \Mockery::mock('MyClass')->makePartial(); This form of mock object will defer all methods not subject to an expectation to the parent class of the mock, i.e. ``MyClass``. Whereas the previous ``shouldIgnoreMissing()`` returned ``null``, this behaviour simply calls the parent's matching method. reference/argument_validation.rst 0000644 00000024771 15110326463 0013304 0 ustar 00 .. index:: single: Argument Validation Argument Validation =================== The arguments passed to the ``with()`` declaration when setting up an expectation determine the criteria for matching method calls to expectations. Thus, we can setup up many expectations for a single method, each differentiated by the expected arguments. Such argument matching is done on a "best fit" basis. This ensures explicit matches take precedence over generalised matches. An explicit match is merely where the expected argument and the actual argument are easily equated (i.e. using ``===`` or ``==``). More generalised matches are possible using regular expressions, class hinting and the available generic matchers. The purpose of generalised matchers is to allow arguments be defined in non-explicit terms, e.g. ``Mockery::any()`` passed to ``with()`` will match **any** argument in that position. Mockery's generic matchers do not cover all possibilities but offers optional support for the Hamcrest library of matchers. Hamcrest is a PHP port of the similarly named Java library (which has been ported also to Python, Erlang, etc). By using Hamcrest, Mockery does not need to duplicate Hamcrest's already impressive utility which itself promotes a natural English DSL. The examples below show Mockery matchers and their Hamcrest equivalent, if there is one. Hamcrest uses functions (no namespacing). .. note:: If you don't wish to use the global Hamcrest functions, they are all exposed through the ``\Hamcrest\Matchers`` class as well, as static methods. Thus, ``identicalTo($arg)`` is the same as ``\Hamcrest\Matchers::identicalTo($arg)`` The most common matcher is the ``with()`` matcher: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo') ->with(1): It tells mockery that it should receive a call to the ``foo`` method with the integer ``1`` as an argument. In cases like this, Mockery first tries to match the arguments using ``===`` (identical) comparison operator. If the argument is a primitive, and if it fails the identical comparison, Mockery does a fallback to the ``==`` (equals) comparison operator. When matching objects as arguments, Mockery only does the strict ``===`` comparison, which means only the same ``$object`` will match: .. code-block:: php $object = new stdClass(); $mock = \Mockery::mock('MyClass'); $mock->shouldReceive("foo") ->with($object); // Hamcrest equivalent $mock->shouldReceive("foo") ->with(identicalTo($object)); A different instance of ``stdClass`` will **not** match. .. note:: The ``Mockery\Matcher\MustBe`` matcher has been deprecated. If we need a loose comparison of objects, we can do that using Hamcrest's ``equalTo`` matcher: .. code-block:: php $mock->shouldReceive("foo") ->with(equalTo(new stdClass)); In cases when we don't care about the type, or the value of an argument, just that any argument is present, we use ``any()``: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive("foo") ->with(\Mockery::any()); // Hamcrest equivalent $mock->shouldReceive("foo") ->with(anything()) Anything and everything passed in this argument slot is passed unconstrained. Validating Types and Resources ------------------------------ The ``type()`` matcher accepts any string which can be attached to ``is_`` to form a valid type check. To match any PHP resource, we could do the following: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive("foo") ->with(\Mockery::type('resource')); // Hamcrest equivalents $mock->shouldReceive("foo") ->with(resourceValue()); $mock->shouldReceive("foo") ->with(typeOf('resource')); It will return a ``true`` from an ``is_resource()`` call, if the provided argument to the method is a PHP resource. For example, ``\Mockery::type('float')`` or Hamcrest's ``floatValue()`` and ``typeOf('float')`` checks use ``is_float()``, and ``\Mockery::type('callable')`` or Hamcrest's ``callable()`` uses ``is_callable()``. The ``type()`` matcher also accepts a class or interface name to be used in an ``instanceof`` evaluation of the actual argument. Hamcrest uses ``anInstanceOf()``. A full list of the type checkers is available at `php.net <http://www.php.net/manual/en/ref.var.php>`_ or browse Hamcrest's function list in `the Hamcrest code <https://github.com/hamcrest/hamcrest-php/blob/master/hamcrest/Hamcrest.php>`_. .. _argument-validation-complex-argument-validation: Complex Argument Validation --------------------------- If we want to perform a complex argument validation, the ``on()`` matcher is invaluable. It accepts a closure (anonymous function) to which the actual argument will be passed. .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive("foo") ->with(\Mockery::on(closure)); If the closure evaluates to (i.e. returns) boolean ``true`` then the argument is assumed to have matched the expectation. .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo') ->with(\Mockery::on(function ($argument) { if ($argument % 2 == 0) { return true; } return false; })); $mock->foo(4); // matches the expectation $mock->foo(3); // throws a NoMatchingExpectationException .. note:: There is no Hamcrest version of the ``on()`` matcher. We can also perform argument validation by passing a closure to ``withArgs()`` method. The closure will receive all arguments passed in the call to the expected method and if it evaluates (i.e. returns) to boolean ``true``, then the list of arguments is assumed to have matched the expectation: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive("foo") ->withArgs(closure); The closure can also handle optional parameters, so if an optional parameter is missing in the call to the expected method, it doesn't necessary means that the list of arguments doesn't match the expectation. .. code-block:: php $closure = function ($odd, $even, $sum = null) { $result = ($odd % 2 != 0) && ($even % 2 == 0); if (!is_null($sum)) { return $result && ($odd + $even == $sum); } return $result; }; $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo')->withArgs($closure); $mock->foo(1, 2); // It matches the expectation: the optional argument is not needed $mock->foo(1, 2, 3); // It also matches the expectation: the optional argument pass the validation $mock->foo(1, 2, 4); // It doesn't match the expectation: the optional doesn't pass the validation .. note:: In previous versions, Mockery's ``with()`` would attempt to do a pattern matching against the arguments, attempting to use the argument as a regular expression. Over time this proved to be not such a great idea, so we removed this functionality, and have introduced ``Mockery::pattern()`` instead. If we would like to match an argument against a regular expression, we can use the ``\Mockery::pattern()``: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo') ->with(\Mockery::pattern('/^foo/')); // Hamcrest equivalent $mock->shouldReceive('foo') ->with(matchesPattern('/^foo/')); The ``ducktype()`` matcher is an alternative to matching by class type: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo') ->with(\Mockery::ducktype('foo', 'bar')); It matches any argument which is an object containing the provided list of methods to call. .. note:: There is no Hamcrest version of the ``ducktype()`` matcher. Capturing Arguments ------------------- If we want to perform multiple validations on a single argument, the ``capture`` matcher provides a streamlined alternative to using the ``on()`` matcher. It accepts a variable which the actual argument will be assigned. .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive("foo") ->with(\Mockery::capture($bar)); This will assign *any* argument passed to ``foo`` to the local ``$bar`` variable to then perform additional validation using assertions. .. note:: The ``capture`` matcher always evaluates to ``true``. As such, we should always perform additional argument validation. Additional Argument Matchers ---------------------------- The ``not()`` matcher matches any argument which is not equal or identical to the matcher's parameter: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo') ->with(\Mockery::not(2)); // Hamcrest equivalent $mock->shouldReceive('foo') ->with(not(2)); ``anyOf()`` matches any argument which equals any one of the given parameters: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo') ->with(\Mockery::anyOf(1, 2)); // Hamcrest equivalent $mock->shouldReceive('foo') ->with(anyOf(1,2)); ``notAnyOf()`` matches any argument which is not equal or identical to any of the given parameters: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo') ->with(\Mockery::notAnyOf(1, 2)); .. note:: There is no Hamcrest version of the ``notAnyOf()`` matcher. ``subset()`` matches any argument which is any array containing the given array subset: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo') ->with(\Mockery::subset(array(0 => 'foo'))); This enforces both key naming and values, i.e. both the key and value of each actual element is compared. .. note:: There is no Hamcrest version of this functionality, though Hamcrest can check a single entry using ``hasEntry()`` or ``hasKeyValuePair()``. ``contains()`` matches any argument which is an array containing the listed values: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo') ->with(\Mockery::contains(value1, value2)); The naming of keys is ignored. ``hasKey()`` matches any argument which is an array containing the given key name: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo') ->with(\Mockery::hasKey(key)); ``hasValue()`` matches any argument which is an array containing the given value: .. code-block:: php $mock = \Mockery::mock('MyClass'); $mock->shouldReceive('foo') ->with(\Mockery::hasValue(value));