Skip to content

Commit

Permalink
Issue mockery#1056: Add configuration to decide how quik definitions …
Browse files Browse the repository at this point in the history
…should behave
  • Loading branch information
danydev committed Jun 9, 2020
1 parent ab3e2a7 commit a9592ed
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 2 deletions.
5 changes: 5 additions & 0 deletions 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)
Expand Down
17 changes: 16 additions & 1 deletion docs/mockery/configuration.rst
Expand Up @@ -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
Expand Down Expand Up @@ -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
----------------------------

Expand Down
18 changes: 18 additions & 0 deletions library/Mockery/Configuration.php
Expand Up @@ -40,6 +40,11 @@ class Configuration
*/
protected $_allowMockingMethodsUnnecessarily = true;

/**
* @var QuickDefinitionsConfiguration
*/
protected $_quickDefinitionsConfiguration;

/**
* Parameter map for use with PHP internal classes.
*
Expand All @@ -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
*
Expand Down Expand Up @@ -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
*
Expand Down
6 changes: 5 additions & 1 deletion library/Mockery/Container.php
Expand Up @@ -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);
Expand Down
56 changes: 56 additions & 0 deletions library/Mockery/QuickDefinitionsConfiguration.php
@@ -0,0 +1,56 @@
<?php
/**
* Mockery
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://github.com/padraic/mockery/blob/master/LICENSE
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to padraic@php.net so we can send you a copy immediately.
*
* @category Mockery
* @package Mockery
* @copyright Copyright (c) 2010 Pádraic Brady (http://blog.astrumfutura.com)
* @license http://github.com/padraic/mockery/blob/master/LICENSE New BSD License
*/

namespace Mockery;

class QuickDefinitionsConfiguration
{
private const QUICK_DEFINITIONS_MODE_MOCK_AT_LEAST_ONCE = 'QUICK_DEFINITIONS_MODE_MOCK_AT_LEAST_ONCE';
private const QUICK_DEFINITIONS_MODE_DEFAULT_EXPECTATION = 'QUICK_DEFINITIONS_MODE_DEFAULT_EXPECTATION';

/**
* Defines what a quick definition should produce.
* Possible options are:
* - self::QUICK_DEFINITIONS_MODE_DEFAULT_EXPECTATION: in this case quick
* definitions define a stub.
* - self::QUICK_DEFINITIONS_MODE_MOCK_AT_LEAST_ONCE: in this case quick
* definitions define a mock with an 'at least once' expectation.
*
* @var string
*/
protected $_quickDefinitionsApplicationMode = self::QUICK_DEFINITIONS_MODE_DEFAULT_EXPECTATION;

/**
* Returns true if quick definitions should setup a stub, returns false when
* quick definitions should setup a mock with 'at least once' expectation.
* When parameter $newValue is specified it sets the configuration with the
* given value.
*/
public function shouldBeCalledAtLeastOnce(?bool $newValue = null): bool
{
if ($newValue !== null) {
$this->_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;
}
}
16 changes: 16 additions & 0 deletions tests/Mockery/ExpectationTest.php
Expand Up @@ -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');
Expand Down

0 comments on commit a9592ed

Please sign in to comment.