├── src ├── PHPUnitVersionRetriever.php ├── ProphesizeOnlyInterfaceTrait7.php ├── ProphesizeOnlyInterfaceTrait.php ├── ExpectationViaCodeOverAnnotationTrait7.php ├── Reporter.php ├── ExpectationViaCodeOverAnnotationTrait.php ├── ProphecyOverMockObjectTrait7.php ├── ProphecyOverMockObjectTrait9.php ├── ExpectOverSetExceptionTrait.php ├── IdentityOverEqualityTrait7.php ├── IdentityOverEqualityTrait.php └── ProphecyOverMockObjectTrait.php ├── composer.json ├── LICENSE └── README.md /src/PHPUnitVersionRetriever.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace PHPUnitGoodPractices\Traits; 13 | 14 | /** 15 | * @internal 16 | */ 17 | final class PHPUnitVersionRetriever 18 | { 19 | public static function getVersion() 20 | { 21 | return class_exists('PHPUnit\Runner\Version') 22 | ? \PHPUnit\Runner\Version::id() 23 | : \PHPUnit_Runner_Version::id(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ProphesizeOnlyInterfaceTrait7.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace PHPUnitGoodPractices\Traits; 13 | 14 | trait ProphesizeOnlyInterfaceTrait7 15 | { 16 | protected function prophesize($classOrInterface = null): \Prophecy\Prophecy\ObjectProphecy 17 | { 18 | if ($classOrInterface && !interface_exists($classOrInterface)) { 19 | Reporter::report('Prophecy shall be created only for (existing) interfaces.'); 20 | } 21 | 22 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phpunitgoodpractices/traits", 3 | "description": "Highly opinionated PHPUnit good practices enforcer.", 4 | "license": "MIT", 5 | "type": "library", 6 | "authors": [ 7 | { 8 | "name": "Dariusz Rumiński", 9 | "email": "dariusz.ruminski@gmail.com" 10 | } 11 | ], 12 | "require": { 13 | "php": "^5.5 || ^7.0 || ^8.0", 14 | "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ~8.5 || ~9.4" 15 | }, 16 | "require-dev": { 17 | "phpspec/prophecy": "^1.10", 18 | "phpunitgoodpractices/polyfill": "^1.1", 19 | "sanmai/phpunit-legacy-adapter": "^6.1 || ^8.0" 20 | }, 21 | "autoload": { 22 | "psr-4": { 23 | "PHPUnitGoodPractices\\Traits\\": "src/" 24 | } 25 | }, 26 | "autoload-dev": { 27 | "psr-4": { 28 | "PHPUnitGoodPractices\\Traits\\Tests\\": "tests/" 29 | } 30 | }, 31 | "config": { 32 | "optimize-autoloader": true, 33 | "sort-packages": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-present Dariusz Rumiński 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 furnished 10 | to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | 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/ProphesizeOnlyInterfaceTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace PHPUnitGoodPractices\Traits; 13 | 14 | if (version_compare(PHPUnitVersionRetriever::getVersion(), '4.5') < 0) { 15 | trait ProphesizeOnlyInterfaceTrait 16 | { 17 | } 18 | } elseif (version_compare(PHPUnitVersionRetriever::getVersion(), '7.0') < 0) { 19 | trait ProphesizeOnlyInterfaceTrait 20 | { 21 | protected function prophesize($classOrInterface = null) 22 | { 23 | if ($classOrInterface && !interface_exists($classOrInterface)) { 24 | Reporter::report('Prophecy shall be created only for (existing) interfaces.'); 25 | } 26 | 27 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 28 | } 29 | } 30 | } else { 31 | trait ProphesizeOnlyInterfaceTrait 32 | { 33 | use ProphesizeOnlyInterfaceTrait7; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/ExpectationViaCodeOverAnnotationTrait7.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * This source file is subject to the MIT license that is bundled 11 | * with this source code in the file LICENSE. 12 | */ 13 | 14 | namespace PHPUnitGoodPractices\Traits; 15 | 16 | use PHPUnit\Util\Test; 17 | 18 | trait ExpectationViaCodeOverAnnotationTrait7 19 | { 20 | public function runBare(): void 21 | { 22 | if (class_exists(Test::class)) { 23 | $expectedException = Test::getExpectedException( 24 | static::class, 25 | $this->getName(false) 26 | ); 27 | } else { 28 | $expectedException = \PHPUnit_Util_Test::getExpectedException( 29 | static::class, 30 | $this->getName(false) 31 | ); 32 | } 33 | 34 | if (false !== $expectedException) { 35 | Reporter::report('Use `->expectExeption*()` or `->setExpectedException*()` instead of `@expectedException*`.'); 36 | } 37 | 38 | parent::runBare(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ❗ THIS PACKAGE IS DEPRECATED ❗ 2 | 3 | With great shape of PHPUnit itself and Static Code Analysers supporting it, this package is no longer needed. 4 | 5 | # PHPUnit Good Practices 6 | 7 | Highly opinionated PHPUnit good practices enforcer. 8 | 9 | ## Available traits 10 | 11 | ### ExpectationViaCodeOverAnnotationTrait 12 | 13 | Expected exception shall be set up via code, not annotations. 14 | 15 | ### ExpectOverSetExceptionTrait 16 | 17 | Expectation shall be set directly over via setter. 18 | 19 | ### IdentityOverEqualityTrait 20 | 21 | Identity assertion (`===`) shall be used over equality ones (`==`). 22 | 23 | ### ProphecyOverMockObjectTrait 24 | 25 | Prophecy shall be used over Mock Objects. 26 | 27 | ### ProphesizeOnlyInterfaceTrait 28 | 29 | Prophecy shall be created only for (existing) interfaces. 30 | 31 | ## Example usage 32 | 33 | ```php 34 | assertEquals(123, 213); // will report non-strict assertion usage 56 | } 57 | } 58 | ``` 59 | -------------------------------------------------------------------------------- /src/Reporter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace PHPUnitGoodPractices\Traits; 13 | 14 | use Closure; 15 | 16 | final class Reporter 17 | { 18 | /** 19 | * @var ?\Closure 20 | */ 21 | private static $customReporter; 22 | 23 | /** 24 | * @var \Closure 25 | */ 26 | private static $defaultReporter; 27 | 28 | /** 29 | * @var bool 30 | */ 31 | private static $useHeader = true; 32 | 33 | /** 34 | * @param $reporter Closure 35 | */ 36 | public static function setCustomReporter(\Closure $reporter) 37 | { 38 | self::$customReporter = $reporter; 39 | } 40 | 41 | public static function clearCustomReporter() 42 | { 43 | self::$customReporter = null; 44 | } 45 | 46 | /** 47 | * @param $use bool 48 | */ 49 | public static function useHeader($use) 50 | { 51 | self::$useHeader = $use; 52 | } 53 | 54 | /** 55 | * @param $issue string 56 | */ 57 | public static function report($issue) 58 | { 59 | if (self::$useHeader) { 60 | $issue = "PHPUnit good practice has been violated.\n{$issue}"; 61 | } 62 | 63 | $reporter = self::$customReporter ?: self::getDefaultReporter(); 64 | $reporter($issue); 65 | } 66 | 67 | /** 68 | * @return \Closure 69 | */ 70 | private static function getDefaultReporter() 71 | { 72 | if (null === self::$defaultReporter) { 73 | self::$defaultReporter = function ($issue) { trigger_error($issue, E_USER_WARNING); }; 74 | } 75 | 76 | return self::$defaultReporter; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/ExpectationViaCodeOverAnnotationTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace PHPUnitGoodPractices\Traits; 13 | 14 | use PHPUnit\Util\Test; 15 | 16 | /* 17 | * Expected exception shall be set up via code, not annotations. 18 | * 19 | * `->expectExeption*()` or `->setExpectedException*()` instead of `@expectedException*` 20 | */ 21 | if (version_compare(PHPUnitVersionRetriever::getVersion(), '7.0.0') < 0) { 22 | trait ExpectationViaCodeOverAnnotationTrait 23 | { 24 | protected function setExpectedExceptionFromAnnotation() 25 | { 26 | if (class_exists(Test::class)) { 27 | $expectedException = Test::getExpectedException( 28 | static::class, 29 | $this->getName(false) 30 | ); 31 | } else { 32 | $expectedException = \PHPUnit_Util_Test::getExpectedException( 33 | static::class, 34 | $this->getName(false) 35 | ); 36 | } 37 | 38 | if (false !== $expectedException) { 39 | Reporter::report('Use `->expectExeption*()` or `->setExpectedException*()` instead of `@expectedException*`.'); 40 | parent::setExpectedExceptionFromAnnotation(); 41 | } 42 | 43 | // no need to call parent method if $expectedException is empty 44 | } 45 | } 46 | } elseif (version_compare(PHPUnitVersionRetriever::getVersion(), '9.0.0') < 0) { 47 | trait ExpectationViaCodeOverAnnotationTrait 48 | { 49 | use ExpectationViaCodeOverAnnotationTrait7; 50 | } 51 | } else { 52 | trait ExpectationViaCodeOverAnnotationTrait 53 | { 54 | // removed from PHPUnit, PHPUnit will crash on it's own 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/ProphecyOverMockObjectTrait7.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * This source file is subject to the MIT license that is bundled 11 | * with this source code in the file LICENSE. 12 | */ 13 | 14 | namespace PHPUnitGoodPractices\Traits; 15 | 16 | trait ProphecyOverMockObjectTrait7 17 | { 18 | public function getMockBuilder($className): \PHPUnit\Framework\MockObject\MockBuilder 19 | { 20 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 21 | 22 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 23 | } 24 | 25 | protected function getMockClass($originalClassName, $methods = [], array $arguments = [], $mockClassName = '', $callOriginalConstructor = false, $callOriginalClone = true, $callAutoload = true, $cloneArguments = false): string 26 | { 27 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 28 | 29 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 30 | } 31 | 32 | protected function getMockForAbstractClass($originalClassName, array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = [], $cloneArguments = false): \PHPUnit\Framework\MockObject\MockObject 33 | { 34 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 35 | 36 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 37 | } 38 | 39 | protected function getMockFromWsdl($wsdlFile, $originalClassName = '', $mockClassName = '', array $methods = [], $callOriginalConstructor = true, array $options = []): \PHPUnit\Framework\MockObject\MockObject 40 | { 41 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 42 | 43 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 44 | } 45 | 46 | protected function ggetMockForTrait($traitName, array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = [], $cloneArguments = false): \PHPUnit\Framework\MockObject\MockObject 47 | { 48 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 49 | 50 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 51 | } 52 | 53 | protected function getObjectForTrait($traitName, array $arguments = [], $traitClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true) 54 | { 55 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 56 | 57 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/ProphecyOverMockObjectTrait9.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * This source file is subject to the MIT license that is bundled 11 | * with this source code in the file LICENSE. 12 | */ 13 | 14 | namespace PHPUnitGoodPractices\Traits; 15 | 16 | trait ProphecyOverMockObjectTrait9 17 | { 18 | public function getMockBuilder($className): \PHPUnit\Framework\MockObject\MockBuilder 19 | { 20 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 21 | 22 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 23 | } 24 | 25 | protected function getMockClass($originalClassName, $methods = [], array $arguments = [], $mockClassName = '', $callOriginalConstructor = false, $callOriginalClone = true, $callAutoload = true, $cloneArguments = false): string 26 | { 27 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 28 | 29 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 30 | } 31 | 32 | protected function getMockForAbstractClass($originalClassName, array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = [], $cloneArguments = false): \PHPUnit\Framework\MockObject\MockObject 33 | { 34 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 35 | 36 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 37 | } 38 | 39 | protected function getMockFromWsdl($wsdlFile, $originalClassName = '', $mockClassName = '', array $methods = [], $callOriginalConstructor = true, array $options = []): \PHPUnit\Framework\MockObject\MockObject 40 | { 41 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 42 | 43 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 44 | } 45 | 46 | protected function ggetMockForTrait($traitName, array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = [], $cloneArguments = false): \PHPUnit\Framework\MockObject\MockObject 47 | { 48 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 49 | 50 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 51 | } 52 | 53 | protected function getObjectForTrait($traitName, array $arguments = [], $traitClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true): object 54 | { 55 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 56 | 57 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/ExpectOverSetExceptionTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace PHPUnitGoodPractices\Traits; 13 | 14 | if (version_compare(PHPUnitVersionRetriever::getVersion(), '4.3') < 0) { 15 | trait ExpectOverSetExceptionTrait 16 | { 17 | public function setExpectedException($exception, $message = '', $code = null) 18 | { 19 | if (null === $exception) { 20 | Reporter::report('Do not pass `null` as expected exception, it violates official interface of method, removes expectation if it is the only parameter or downgrade it to raw Exception if there are more parameters, and will crash on newer `expectException*` method.'); 21 | } elseif (version_compare(PHPUnitVersionRetriever::getVersion(), '5.2') >= 0) { 22 | Reporter::report('Use `->expectExeption*()` methods instead of `->setExpectedException()`.'); 23 | } 24 | 25 | \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 26 | } 27 | } 28 | } elseif (version_compare(PHPUnitVersionRetriever::getVersion(), '6.0') < 0) { 29 | trait ExpectOverSetExceptionTrait 30 | { 31 | public function setExpectedException($exception, $message = '', $code = null) 32 | { 33 | if (null === $exception) { 34 | Reporter::report('Do not pass `null` as expected exception, it violates official interface of method, removes expectation if it is the only parameter or downgrade it to raw Exception if there are more parameters, and will crash on newer `expectException*` method.'); 35 | } elseif (version_compare(PHPUnitVersionRetriever::getVersion(), '5.2') >= 0) { 36 | Reporter::report('Use `->expectExeption*()` methods instead of `->setExpectedException()`.'); 37 | } 38 | 39 | \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 40 | } 41 | 42 | public function setExpectedExceptionRegExp($exception, $message = '', $code = null) 43 | { 44 | if (null === $exception) { 45 | Reporter::report('Do not pass `null` as expected exception, it violates official interface of method, removes expectation if it is the only parameter or downgrade it to raw Exception if there are more parameters, and will crash on newer `expectException*` method.'); 46 | } elseif (version_compare(PHPUnitVersionRetriever::getVersion(), '5.2') >= 0) { 47 | Reporter::report('Use `->expectExeption*()` methods instead of `->setExpectedExceptionRegExp()`.'); 48 | } 49 | 50 | \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 51 | } 52 | } 53 | } else { 54 | trait ExpectOverSetExceptionTrait 55 | { 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/IdentityOverEqualityTrait7.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * This source file is subject to the MIT license that is bundled 11 | * with this source code in the file LICENSE. 12 | */ 13 | 14 | namespace PHPUnitGoodPractices\Traits; 15 | 16 | trait IdentityOverEqualityTrait7 17 | { 18 | public static function assertEquals($expected, $actual, string $message = '', float $delta = 0.0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): void 19 | { 20 | $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); 21 | 22 | // sometimes, PHPUnit calls `assertEquals` instead of `assertSame` internally, we allow that 23 | if (!\in_array( 24 | $trace[1]['function'], 25 | [ 26 | 'assertJsonStringEqualsJsonString', 27 | 'assertSame', 28 | 'assertStringEqualsFile', 29 | 'assertXmlStringEqualsXmlString', 30 | ], 31 | true 32 | )) { 33 | Reporter::report('Use `->assertSame()` instead of `->assertEquals()`.'); 34 | } 35 | 36 | \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 37 | } 38 | 39 | public static function assertNotEquals($expected, $actual, string $message = '', $delta = 0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false): void 40 | { 41 | $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); 42 | 43 | // sometimes, PHPUnit calls `assertEquals` instead of `assertSame` internally, we allow that 44 | if ('assertNotSame' !== $trace[1]['function']) { 45 | Reporter::report('Use `->assertNotSame()` instead of `->assertNotEquals()`.'); 46 | } 47 | 48 | \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 49 | } 50 | 51 | public static function assertAttributeEquals($expected, string $actualAttributeName, $actualClassOrObject, string $message = '', float $delta = 0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): void 52 | { 53 | // need to override the method, as original on v4 is not using Late Static Binding 54 | static::assertEquals( 55 | $expected, 56 | self::readAttribute($actualClassOrObject, $actualAttributeName), 57 | $message, 58 | $delta, 59 | $maxDepth, 60 | $canonicalize, 61 | $ignoreCase 62 | ); 63 | } 64 | 65 | public static function assertAttributeNotEquals($expected, string $actualAttributeName, $actualClassOrObject, string $message = '', float $delta = 0, int $maxDepth = 10, bool $canonicalize = false, bool $ignoreCase = false): void 66 | { 67 | // need to override the method, as original on v4 is not using Late Static Binding 68 | static::assertNotEquals( 69 | $expected, 70 | self::readAttribute($actualClassOrObject, $actualAttributeName), 71 | $message, 72 | $delta, 73 | $maxDepth, 74 | $canonicalize, 75 | $ignoreCase 76 | ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/IdentityOverEqualityTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace PHPUnitGoodPractices\Traits; 13 | 14 | /* 15 | * Identity (`===`) assertions shall be used over equality (`==`) ones. 16 | * 17 | * `assertSame` instead of `assertEquals` 18 | * `assertNotSame` instead of `assertNotEquals` 19 | * `assertAttributeSame` instead of `assertAttributeEquals` 20 | * `assertAttributeNotSame` instead of `assertAttributeNotEquals` 21 | */ 22 | if (version_compare(PHPUnitVersionRetriever::getVersion(), '7.0.0') < 0) { 23 | trait IdentityOverEqualityTrait 24 | { 25 | public static function assertEquals($expected, $actual, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false) 26 | { 27 | $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); 28 | 29 | // sometimes, PHPUnit calls `assertEquals` instead of `assertSame` internally, we allow that 30 | if (!\in_array( 31 | $trace[1]['function'], 32 | [ 33 | 'assertJsonStringEqualsJsonString', 34 | 'assertSame', 35 | 'assertStringEqualsFile', 36 | 'assertXmlStringEqualsXmlString', 37 | ], 38 | true 39 | )) { 40 | Reporter::report('Use `->assertSame()` instead of `->assertEquals()`.'); 41 | } 42 | 43 | \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 44 | } 45 | 46 | public static function assertNotEquals($expected, $actual, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false) 47 | { 48 | $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); 49 | 50 | // sometimes, PHPUnit calls `assertEquals` instead of `assertSame` internally, we allow that 51 | if ('assertNotSame' !== $trace[1]['function']) { 52 | Reporter::report('Use `->assertNotSame()` instead of `->assertNotEquals()`.'); 53 | } 54 | 55 | \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 56 | } 57 | 58 | public static function assertAttributeEquals($expected, $actualAttributeName, $actualClassOrObject, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false) 59 | { 60 | // need to override the method, as original on v4 is not using Late Static Binding 61 | static::assertEquals( 62 | $expected, 63 | self::readAttribute($actualClassOrObject, $actualAttributeName), 64 | $message, 65 | $delta, 66 | $maxDepth, 67 | $canonicalize, 68 | $ignoreCase 69 | ); 70 | } 71 | 72 | public static function assertAttributeNotEquals($expected, $actualAttributeName, $actualClassOrObject, $message = '', $delta = 0.0, $maxDepth = 10, $canonicalize = false, $ignoreCase = false) 73 | { 74 | // need to override the method, as original on v4 is not using Late Static Binding 75 | static::assertNotEquals( 76 | $expected, 77 | self::readAttribute($actualClassOrObject, $actualAttributeName), 78 | $message, 79 | $delta, 80 | $maxDepth, 81 | $canonicalize, 82 | $ignoreCase 83 | ); 84 | } 85 | } 86 | } else { 87 | trait IdentityOverEqualityTrait 88 | { 89 | use IdentityOverEqualityTrait7; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/ProphecyOverMockObjectTrait.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace PHPUnitGoodPractices\Traits; 13 | 14 | if (version_compare(PHPUnitVersionRetriever::getVersion(), '4.5') < 0) { 15 | trait ProphecyOverMockObjectTrait 16 | { 17 | } 18 | } elseif (version_compare(PHPUnitVersionRetriever::getVersion(), '5.4') < 0) { 19 | trait ProphecyOverMockObjectTrait 20 | { 21 | public function getMockBuilder($className) 22 | { 23 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 24 | 25 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 26 | } 27 | 28 | public function getMockForAbstractClass($originalClassName, array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = [], $cloneArguments = false) 29 | { 30 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 31 | 32 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 33 | } 34 | 35 | public function getMockForTrait($traitName, array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = [], $cloneArguments = false) 36 | { 37 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 38 | 39 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 40 | } 41 | 42 | protected function getMockClass($originalClassName, $methods = [], array $arguments = [], $mockClassName = '', $callOriginalConstructor = false, $callOriginalClone = true, $callAutoload = true, $cloneArguments = false) 43 | { 44 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 45 | 46 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 47 | } 48 | 49 | protected function getMockFromWsdl($wsdlFile, $originalClassName = '', $mockClassName = '', array $methods = [], $callOriginalConstructor = true, array $options = []) 50 | { 51 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 52 | 53 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 54 | } 55 | 56 | protected function getObjectForTrait($traitName, array $arguments = [], $traitClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $cloneArguments = false) 57 | { 58 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 59 | 60 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 61 | } 62 | } 63 | } elseif (version_compare(PHPUnitVersionRetriever::getVersion(), '6.0') < 0) { 64 | trait ProphecyOverMockObjectTrait 65 | { 66 | public function getMockBuilder($className) 67 | { 68 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 69 | 70 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 71 | } 72 | 73 | protected function getMockClass($originalClassName, $methods = [], array $arguments = [], $mockClassName = '', $callOriginalConstructor = false, $callOriginalClone = true, $callAutoload = true, $cloneArguments = false) 74 | { 75 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 76 | 77 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 78 | } 79 | 80 | protected function getMockForAbstractClass($originalClassName, array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = [], $cloneArguments = false) 81 | { 82 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 83 | 84 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 85 | } 86 | 87 | protected function getMockFromWsdl($wsdlFile, $originalClassName = '', $mockClassName = '', array $methods = [], $callOriginalConstructor = true, array $options = []) 88 | { 89 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 90 | 91 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 92 | } 93 | 94 | protected function getMockForTrait($traitName, array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = [], $cloneArguments = false) 95 | { 96 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 97 | 98 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 99 | } 100 | 101 | protected function getObjectForTrait($traitName, array $arguments = [], $traitClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $cloneArguments = false) 102 | { 103 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 104 | 105 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 106 | } 107 | } 108 | } elseif (version_compare(PHPUnitVersionRetriever::getVersion(), '7.0.0') < 0) { 109 | trait ProphecyOverMockObjectTrait 110 | { 111 | public function getMockBuilder($className) 112 | { 113 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 114 | 115 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 116 | } 117 | 118 | protected function getMockClass($originalClassName, $methods = [], array $arguments = [], $mockClassName = '', $callOriginalConstructor = false, $callOriginalClone = true, $callAutoload = true, $cloneArguments = false) 119 | { 120 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 121 | 122 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 123 | } 124 | 125 | protected function getMockForAbstractClass($originalClassName, array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = [], $cloneArguments = false) 126 | { 127 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 128 | 129 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 130 | } 131 | 132 | protected function getMockFromWsdl($wsdlFile, $originalClassName = '', $mockClassName = '', array $methods = [], $callOriginalConstructor = true, array $options = []) 133 | { 134 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 135 | 136 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 137 | } 138 | 139 | protected function getMockForTrait($traitName, array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = [], $cloneArguments = false) 140 | { 141 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 142 | 143 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 144 | } 145 | 146 | protected function getObjectForTrait($traitName, array $arguments = [], $traitClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true) 147 | { 148 | Reporter::report('Use `Prophecy` instead of basic `MockObject`.'); 149 | 150 | return \call_user_func_array([parent::class, __FUNCTION__], \func_get_args()); 151 | } 152 | } 153 | } elseif (version_compare(PHPUnitVersionRetriever::getVersion(), '9.0.0') < 0) { 154 | trait ProphecyOverMockObjectTrait 155 | { 156 | use ProphecyOverMockObjectTrait7; 157 | } 158 | } else { 159 | trait ProphecyOverMockObjectTrait 160 | { 161 | use ProphecyOverMockObjectTrait9; 162 | } 163 | } 164 | --------------------------------------------------------------------------------