-
Notifications
You must be signed in to change notification settings - Fork 153
Mocking interface with final return types fails since 6.5.x #388
Comments
The problem is that |
@sebastianbergmann I am not mocking the final class. I am mocking the interface. And this works in PHPUnit 6.4. |
The problem is that phpunit must implement the method in the mock. The default behavior is that it returns a new mock of the return type hint (if given), wich is impossible as you can't mock final classes. |
See #386. As I pointed there, it could be possible to mock such a method if it returns the typehint with |
That leaves me with two questions.
|
|
Well that is a problem indeed. I get that the default behaviour of a mock that all its methods return mocks of the return type. However, why would you not create that mock once the method is called. And thereby allowing to override the default behaviour via |
<?php
final class Foo
{
}
interface Bar
{
public function baz(): Foo;
}
class Test extends PHPUnit\Framework\TestCase
{
public function testOne()
{
$stub = $this->createMock(Bar::class);
$this->assertInstanceOf(Bar::class, $stub);
$this->assertInstanceOf(Foo::class, $stub->baz());
}
} phpunit-mock-objects 4.0
phpunit-mock-objects 5.0
|
There are two differences here between phpunit-mock-objects 4.0 and phpunit-mock-objects 5.0:
Of course, such a PHP compiler error must not be triggered and a PHPUnit warning should be raised instead. But I definitely prefer to raise this issue at the point in time when the stub is created rather then when a problematic method is invoked for the first time. |
namespace Genkgo\TestFramework;
use PHPUnit\Framework\TestCase;
final class DomainNameCollection {}
interface DomainProviderInterface {
public function provide(): DomainNameCollection;
public function persist(DomainNameCollection $domains): void;
}
final class Test extends TestCase {
public function test() {
$mock = $this->createMock(DomainProviderInterface::class);
$this->assertInstanceOf(DomainProviderInterface::class, $mock);
}
} Case 1: PHPUnit 6.4.4
Case 2: PHPUnit 6.5.1
|
@sebastianbergmann However, if I do execute your example, I get the same result as you do. So what makes my case different from yours? |
@sebastianbergmann Maybe you can see what you get when you try my case in PHPUnit 6.4.4. Does it pass? |
At first glance, #388 (comment) seems to make sense. I will have investigate this. However, probably not over the weekend. |
@sebastianbergmann Sounds good. You may want to consider to create a new tag 6.5.2 that uses the old phpunit mock objects. Will prevent other people hitting the bug and fixing this might take a while. |
@frederikbosch Unfortunately, PHPUnit 6.5 is not compatible with phpunit-mock-objects 4.0. |
With diff --git a/src/Generator.php b/src/Generator.php
index 643b676..7c28df7 100644
--- a/src/Generator.php
+++ b/src/Generator.php
@@ -1029,39 +1029,7 @@ private function generateMockedMethodDefinition($className, $methodName, $cloneA
*/
private function canMockMethod(ReflectionMethod $method)
{
- return !($method->isConstructor() || $method->isFinal() || !$this->canReturnTypeBeStubbed($method) || $method->isPrivate() || $this->isMethodNameBlacklisted($method->getName()));
- }
-
- /**
- * @param ReflectionMethod $method
- *
- * @return bool
- *
- * @throws \ReflectionException
- */
- private function canReturnTypeBeStubbed(ReflectionMethod $method)
- {
- if (!$method->hasReturnType()) {
- return true;
- }
-
- if (PHP_VERSION_ID >= 70100 && $method->getReturnType()->allowsNull()) {
- return true;
- }
-
- $returnType = (string) $method->getReturnType();
-
- if ($returnType === \Generator::class || $returnType === \Closure::class) {
- return true;
- }
-
- if (\class_exists($returnType)) {
- $class = new ReflectionClass($returnType);
-
- return !$class->isFinal();
- }
-
- return true;
+ return !($method->isConstructor() || $method->isFinal() || $method->isPrivate() || $this->isMethodNameBlacklisted($method->getName()));
}
/** I get the same result for PHPUnit 6.4 and PHPUnit 6.5 with the example from #388 (comment). |
@frederikbosch @weierophinney Does the patch shown in #388 (comment) solve your problem? |
Thanks for the fast help! |
@sebastianbergmann I can confirm that with PHPUnit 5.6.2 this problem has been fixed. Thanks! |
@sebastianbergmann My problem is solved too. Thanks again for your fast handling. |
Since version 6.5.0 I have problems with mocking a specific class:
DomainProviderInterface
. It seems to be related to the methodprovide
that is part of the class.Above code works in 6.4.x, but fails in 6.5.x. I tested both 6.5.0 and 6.5.1.
The text was updated successfully, but these errors were encountered: