Skip to content

Commit

Permalink
Issue mockery#1056: Add option to allow\disallow mocking methods unne…
Browse files Browse the repository at this point in the history
…cessarily

for default expectations set through quick definitions
  • Loading branch information
danydev committed May 21, 2020
1 parent eca936d commit a111f33
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 8 deletions.
20 changes: 13 additions & 7 deletions docs/mockery/configuration.rst
Expand Up @@ -10,6 +10,8 @@ currently present include:

* Option to allow/disallow the mocking of methods which do not actually exist
fulfilled (i.e. unused)
* Option to allow/disallow the existence of default expectations defined with
quick definitions which are never fulfilled (i.e. unused)
* Setter/Getter for added a parameter map for internal PHP class methods
(``Reflection`` cannot detect these automatically)

Expand All @@ -18,19 +20,23 @@ 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.
Allowing unfulfilled default expectations defined with quick definitions means
unnecessary mock expectations go unnoticed, cluttering up test code, and
potentially confusing test readers.

You may allow or disallow this behaviour (whether for whole test suites or
just select tests) by using the following call:
You may allow or disallow these behaviours (whether for whole test suites or
just select tests) by using one or both of the following two calls:

.. code-block:: php
\Mockery::getConfiguration()->allowMockingNonExistentMethods(bool);
\Mockery::getConfiguration()->allowMockingQuickDefaultExpectationMethodsUnnecessarily(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.
Passing a true allows the behaviour, false disallows it. Both take effect
immediately until switched back. In both cases, if either behaviour is detected
when not allowed, it will result in an Exception being thrown at that point.
Note that disallowing these behaviours should be carefully considered since they
necessarily remove at least some of Mockery's flexibility.

The other two methods are:

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

/**
* Boolean assertion of whether we ignore unnecessary mocking of methods,
* for default expectations defined with quick definitions. i.e. when
* method default expectations are made and then never called. Essentially
* such expectations are not required and are just taking up test space.
*
* @var bool
*/
protected $_allowQuickMockingDefaultExpectationMethodsUnnecessarily = true;

/**
* Parameter map for use with PHP internal classes.
*
Expand Down Expand Up @@ -103,6 +113,28 @@ public function mockingMethodsUnnecessarilyAllowed()
return $this->_allowMockingMethodsUnnecessarily;
}

/**
* Set boolean to allow/prevent unnecessary mocking of methods for default
* expectations defined in quick definitions.
*
* @param bool $flag
*/
public function allowMockingQuickDefaultExpectationMethodsUnnecessarily($flag = true)
{
$this->_allowQuickMockingDefaultExpectationMethodsUnnecessarily = (bool) $flag;
}

/**
* Return flag indicating whether mocking non-existent methods for default
* expectations defined in quick definitions is allowed.
*
* @return bool
*/
public function mockingQuickDefaultExpectationMethodsUnnecessarilyAllowed()
{
return $this->_allowQuickMockingDefaultExpectationMethodsUnnecessarily;
}

/**
* Set a parameter map (array of param signature strings) for the method
* of an internal PHP class.
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()->mockingQuickDefaultExpectationMethodsUnnecessarilyAllowed()) {
$mock->shouldReceive($quickdefs)->byDefault();
} else {
$mock->shouldReceive($quickdefs)->byDefault()->atLeast()->once();
}
}
if (!empty($expectationClosure)) {
$expectationClosure($mock);
Expand Down
16 changes: 16 additions & 0 deletions tests/Mockery/ExpectationTest.php
Expand Up @@ -1866,6 +1866,22 @@ public function testGlobalConfigMayForbidMockingNonExistentMethodsOnObjects()
Mockery::close();
}

public function testGlobalConfigMayForbidMockingQuickDefaultExpectationMethodsUnnecessarily()
{
\Mockery::getConfiguration()->allowMockingQuickDefaultExpectationMethodsUnnecessarily(false);
mock(array('foo'=>1));
$this->expectException(\Mockery\Exception\InvalidCountException::class);
Mockery::close();
}

public function testGlobalConfigMayAllowMockingQuickDefaultExpectationMethodsUnnecessarily()
{
\Mockery::getConfiguration()->allowMockingQuickDefaultExpectationMethodsUnnecessarily(true);
mock(array('foo'=>1));
$this->expectNotToPerformAssertions();
Mockery::close();
}

public function testAnExampleWithSomeExpectationAmends()
{
$service = mock('MyService');
Expand Down

0 comments on commit a111f33

Please sign in to comment.