├── composer.json ├── CONTRIBUTING.md ├── LICENSE ├── src └── EasyMock.php └── README.md /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mnapoli/phpunit-easymock", 3 | "description": "Helpers to build PHPUnit mocks", 4 | "keywords": ["phpunit", "mock"], 5 | "homepage": "https://github.com/mnapoli/phpunit-easymock", 6 | "license": "MIT", 7 | "type": "library", 8 | "autoload": { 9 | "psr-4": { 10 | "EasyMock\\": "src/" 11 | } 12 | }, 13 | "autoload-dev": { 14 | "psr-4": { 15 | "EasyMock\\Test\\": "tests/" 16 | } 17 | }, 18 | "require": { 19 | "php": ">=7.3", 20 | "phpunit/phpunit": "^8.5|^9.0|^10.0|^11.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | First of all, **thank you** for contributing! 4 | 5 | Here are a few rules to follow in order to ease code reviews and merging: 6 | 7 | - follow [PSR-1](http://www.php-fig.org/psr/1/) and [PSR-2](http://www.php-fig.org/psr/2/) 8 | - run the test suite 9 | - write (or update) unit tests when applicable 10 | - write documentation for new features 11 | - use [commit messages that make sense](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) 12 | 13 | One may ask you to [squash your commits](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html) too. This is used to "clean" your pull request before merging it (we don't want commits such as `fix tests`, `fix 2`, `fix 3`, etc.). 14 | 15 | When creating your pull request on GitHub, please write a description which gives the context and/or explains why you are creating it. 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Matthieu Napoli 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/EasyMock.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | trait EasyMock 16 | { 17 | /** 18 | * Mock the given class. 19 | * 20 | * Methods not specified in $methods will be mocked to return null (default PHPUnit behavior). 21 | * The class constructor will *not* be called. 22 | * 23 | * @param string|MockObject $classname The class to mock. Can also be an existing mock to mock new methods. 24 | * @param array $methods Array of values to return, indexed by the method name. 25 | */ 26 | protected function easyMock($classname, array $methods = []): MockObject 27 | { 28 | $mock = $classname instanceof MockObject ? $classname : $this->createMock($classname); 29 | 30 | foreach ($methods as $method => $return) { 31 | $this->mockMethod($mock, $method, new AnyInvokedCount(), $return); 32 | } 33 | 34 | return $mock; 35 | } 36 | 37 | /** 38 | * Mock the given class by spying on method calls. 39 | * 40 | * This is the same as EasyMock::mock() except this assert that methods are called at least once. 41 | * 42 | * @see easyMock() 43 | * 44 | * @param string|MockObject $classname The class to mock. Can also be an existing mock to mock new methods. 45 | * @param array $methods Array of values to return, indexed by the method name. 46 | */ 47 | protected function easySpy($classname, array $methods = []): MockObject 48 | { 49 | $mock = $classname instanceof MockObject ? $classname : $this->createMock($classname); 50 | 51 | foreach ($methods as $method => $return) { 52 | $this->mockMethod($mock, $method, new InvokedAtLeastOnce(), $return); 53 | } 54 | 55 | return $mock; 56 | } 57 | 58 | private function mockMethod(MockObject $mock, string $method, InvocationOrder $invocation, $return): void 59 | { 60 | $methodAssertion = $mock->expects($invocation)->method($method); 61 | 62 | if (is_callable($return)) { 63 | $methodAssertion->willReturnCallback($return); 64 | } elseif ($return instanceof \Exception) { 65 | $methodAssertion->willThrowException($return); 66 | } else { 67 | $methodAssertion->willReturn($return); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHPUnit EasyMock 2 | 3 | Helpers to build PHPUnit mock objects easily. 4 | 5 | [![Total Downloads](https://poser.pugx.org/mnapoli/phpunit-easymock/downloads)](https://packagist.org/packages/mnapoli/phpunit-easymock) 6 | 7 | ## Why? 8 | 9 | This library is **not** a mocking library. It's just a few helpers to write the most common mocks more easily. 10 | 11 | It doesn't reinvent anything and is not intended to cover every use case: only the most common ones. 12 | 13 | ## Installation 14 | 15 | ```bash 16 | $ composer require --dev mnapoli/phpunit-easymock 17 | ``` 18 | 19 | To be able to use EasyMock in your tests **you must include the trait in your class**: 20 | 21 | ```php 22 | class MyTest extends \PHPUnit\Framework\TestCase 23 | { 24 | use \EasyMock\EasyMock; 25 | 26 | // ... 27 | } 28 | ``` 29 | 30 | ## Usage 31 | 32 | Here is what a very common PHPUnit mock looks like: 33 | 34 | ```php 35 | $mock = $this->createMock('My\Class'); 36 | 37 | $mock->expect($this->any()) 38 | ->method('sayHello') 39 | ->willReturn('Hello'); 40 | ``` 41 | 42 | Yuck! 43 | 44 | Here is how to write it with EasyMock: 45 | 46 | ```php 47 | $mock = $this->easyMock('My\Class', [ 48 | 'sayHello' => 'Hello', 49 | ]); 50 | ``` 51 | 52 | What if you want to assert that the method is called once (i.e. `$mock->expect($this->once())`)? Use `spy()` instead: 53 | 54 | ```php 55 | $mock = $this->easySpy('My\Class', [ 56 | 'sayHello' => 'Hello', 57 | ]); 58 | ``` 59 | 60 | ### Features 61 | 62 | You can mock methods so that they return values: 63 | 64 | ```php 65 | $mock = $this->easyMock('My\Class', [ 66 | 'sayHello' => 'Hello', 67 | ]); 68 | ``` 69 | 70 | Or so that they use a callback: 71 | 72 | ```php 73 | $mock = $this->easyMock('My\Class', [ 74 | 'sayHello' => function ($name) { 75 | return 'Hello ' . $name; 76 | }, 77 | ]); 78 | ``` 79 | 80 | You can also have methods throw exceptions by providing an `Exception` instance: 81 | 82 | ```php 83 | $mock = $this->easyMock('My\Class', [ 84 | 'sayHello' => new \RuntimeException('Whoops'), 85 | ]); 86 | ``` 87 | 88 | It is possible to call the `mock()` method again on an existing mock: 89 | 90 | ```php 91 | $mock = $this->easyMock('My\Class'); 92 | 93 | $mock = $this->easyMock($mock, [ 94 | 'sayHello' => 'Hello', 95 | ]); 96 | ``` 97 | 98 | ### What if? 99 | 100 | If you want to use assertions or other PHPUnit features, just do it: 101 | 102 | ```php 103 | $mock = $this->easyMock('My\Class', [ 104 | 'sayHello' => 'hello', 105 | ]); 106 | 107 | $mock->expects($this->once()) 108 | ->method('sayGoodbye') 109 | ->willReturn('Goodbye'); 110 | ``` 111 | 112 | Mocks are plain PHPUnit mocks, nothing special here. 113 | 114 | ## Contributing 115 | 116 | See the [CONTRIBUTING](CONTRIBUTING.md) file. 117 | 118 | ## License 119 | 120 | Released under the [MIT license](LICENSE). 121 | --------------------------------------------------------------------------------