diff --git a/CHANGELOG.md b/CHANGELOG.md index b69f2a4a0..b3b93fe78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Change Log +## 1.4.1 (XXXX-XX-XX) + +* Allow quick definitions to use 'at least once' expectation + `\Mockery::getConfiguration()->getQuickDefinitions()->shouldBeCalledAtLeastOnce(true)` (#1056) + ## 1.4.0 (2020-05-19) * Fix andAnyOthers() to properly match earlier expectations (#1051) diff --git a/docs/mockery/configuration.rst b/docs/mockery/configuration.rst index 3a89579cf..aa2a64a9e 100644 --- a/docs/mockery/configuration.rst +++ b/docs/mockery/configuration.rst @@ -5,13 +5,15 @@ 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 two +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 @@ -47,6 +49,19 @@ 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. +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 ---------------------------- diff --git a/library/Mockery/Configuration.php b/library/Mockery/Configuration.php index 125f1541a..858e2de0c 100644 --- a/library/Mockery/Configuration.php +++ b/library/Mockery/Configuration.php @@ -40,6 +40,11 @@ class Configuration */ protected $_allowMockingMethodsUnnecessarily = true; + /** + * @var QuickDefinitionsConfiguration + */ + protected $_quickDefinitionsConfiguration; + /** * Parameter map for use with PHP internal classes. * @@ -57,6 +62,11 @@ class Configuration */ protected $_reflectionCacheEnabled = true; + public function __construct() + { + $this->_quickDefinitionsConfiguration = new QuickDefinitionsConfiguration(); + } + /** * Set boolean to allow/prevent mocking of non-existent methods * @@ -154,6 +164,14 @@ public function getConstantsMap() return $this->_constantsMap; } + /** + * Returns the quick definitions configuration + */ + public function getQuickDefinitions(): QuickDefinitionsConfiguration + { + return $this->_quickDefinitionsConfiguration; + } + /** * Disable reflection caching * diff --git a/library/Mockery/Container.php b/library/Mockery/Container.php index e50a15611..cfdb4cb67 100644 --- a/library/Mockery/Container.php +++ b/library/Mockery/Container.php @@ -233,7 +233,11 @@ public function mock(...$args) $mock->mockery_init($this, $config->getTargetObject(), $config->isInstanceMock()); if (!empty($quickdefs)) { - $mock->shouldReceive($quickdefs)->byDefault(); + if (\Mockery::getConfiguration()->getQuickDefinitions()->shouldBeCalledAtLeastOnce()) { + $mock->shouldReceive($quickdefs)->atLeast()->once(); + } else { + $mock->shouldReceive($quickdefs)->byDefault(); + } } if (!empty($expectationClosure)) { $expectationClosure($mock); diff --git a/library/Mockery/QuickDefinitionsConfiguration.php b/library/Mockery/QuickDefinitionsConfiguration.php new file mode 100644 index 000000000..b0eea6623 --- /dev/null +++ b/library/Mockery/QuickDefinitionsConfiguration.php @@ -0,0 +1,56 @@ +_quickDefinitionsApplicationMode = $newValue + ? self::QUICK_DEFINITIONS_MODE_MOCK_AT_LEAST_ONCE + : self::QUICK_DEFINITIONS_MODE_DEFAULT_EXPECTATION; + } + + return $this->_quickDefinitionsApplicationMode === self::QUICK_DEFINITIONS_MODE_MOCK_AT_LEAST_ONCE; + } +} diff --git a/tests/Mockery/ExpectationTest.php b/tests/Mockery/ExpectationTest.php index 19b1d44e1..07a869948 100644 --- a/tests/Mockery/ExpectationTest.php +++ b/tests/Mockery/ExpectationTest.php @@ -1877,6 +1877,22 @@ public function testGlobalConfigMayForbidMockingNonExistentMethodsOnObjects() Mockery::close(); } + public function testGlobalConfigQuickDefinitionsConfigurationDefaultExpectation() + { + \Mockery::getConfiguration()->getQuickDefinitions()->shouldBeCalledAtLeastOnce(false); + mock(array('foo'=>1)); + $this->expectNotToPerformAssertions(); + Mockery::close(); + } + + public function testGlobalConfigQuickDefinitionsConfigurationMockAtLeastOnce() + { + \Mockery::getConfiguration()->getQuickDefinitions()->shouldBeCalledAtLeastOnce(true); + mock(array('foo'=>1)); + $this->expectException(\Mockery\Exception\InvalidCountException::class); + Mockery::close(); + } + public function testAnExampleWithSomeExpectationAmends() { $service = mock('MyService');