Open oleg-andreyev opened 4 years ago
Thank you for your report.
Please provide a minimal, self-contained, reproducing test case that shows the problem you are reporting.
Without such a minimal, self-contained, reproducing test case I will not be able to investigate this issue.
@sebastianbergmann , I have sucessfully reproduced the issue (PHPUnit 9.6.3 by Sebastian Bergmann and contributors.
) To reproduce you can use TestCase
and mock the doctrine's entity manager, have the entity manager match the getRepository
method with
two repository classes consecutively (order does not matter); you will see the matcher exception. Example:
// doctrine entities
class Order {}
class Customer {}
// doctrine repositories
class OrderRepository {}
class CustomerRepository {}
// Test Subject
class Order {
public function __construct(EntityManagerInterface $em) {
$order = $this->$em->getRepository(OrderRepository::class)->findBy(['id' => 1]);
}
}
class OrderTest extends TestCase
{
protected function setUp(): void {
$this->em = $this->createMock(EntityManagerInterface::class);
$this->customerRepositoryMock = $this->createMock(CustomerRepository::class);
$this->orderRepositoryMock = $this->createMock(OrderRepository::class);
$this->em->method('getRepository')->with(Customer::class)
->willReturn($this->customerRepositoryMock);
$this->em->method('getRepository')->with(Order::class)
->willReturn($this->orderRepositoryMock);
}
}
// Then try test a class that uses these mock and try to get anything from these repositories,
// it will throw.
// I hope I could make it reproducible for you.
Thank you for your report.
Please provide a minimal, self-contained, reproducing test case that shows the problem you are reporting.
Without such a minimal, self-contained, reproducing test case I will not be able to investigate this issue.
Lol. It's been 2y+, somehow I've missed this notification. It's irrelevant for me atm. 💪👍
Sorry, but something that uses Doctrine's entity manager is neither minimal nor self-contained.
Latest 10.5
branch:
kub@:~/code/sebastianbergmann/phpunit(10.5)$ cat test.php
<?php
interface I { public function get(string $x): int; }
class C1 {}
class C2 {}
class Test extends PHPUnit\Framework\TestCase
{
private $mock;
protected function setUp(): void
{
$this->mock = $this->createMock(I::class);
$this->mock->method('get')->with(C1::class)
->willReturn(1);
$this->mock->method('get')->with(C2::class)
->willReturn(2);
}
public function testSomething(): void
{
// 1 of the 2 lines below can be commented out and exception is still thrown
$this->mock->get(C1::class);
$this->mock->get(C2::class);
$this->assertTrue(true);
}
}
kub@:~/code/sebastianbergmann/phpunit(10.5)$ php phpunit test.php
PHPUnit 10.5.32-4-g8d77a5c4e by Sebastian Bergmann and contributors.
Runtime: PHP 8.3.11
Configuration: /home/kuba/code/sebastianbergmann/phpunit/phpunit.xml
F 1 / 1 (100%)
Time: 00:00.005, Memory: 8.00 MB
There was 1 failure:
1) Test::testSomething
Expectation failed for method name is "get" when invoked zero or more times
Parameter 0 for invocation I::get('C1'): int does not match expected value.
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'C2'
+'C1'
/home/kuba/code/sebastianbergmann/phpunit/src/Framework/MockObject/Runtime/Matcher.php:110
/home/kuba/code/sebastianbergmann/phpunit/src/Framework/MockObject/Runtime/InvocationHandler.php:109
/home/kuba/code/sebastianbergmann/phpunit/test.php:23
/home/kuba/code/sebastianbergmann/phpunit/src/Framework/TestCase.php:1188
/home/kuba/code/sebastianbergmann/phpunit/src/Framework/TestCase.php:687
/home/kuba/code/sebastianbergmann/phpunit/src/Framework/TestRunner.php:106
/home/kuba/code/sebastianbergmann/phpunit/src/Framework/TestCase.php:517
/home/kuba/code/sebastianbergmann/phpunit/src/Framework/TestSuite.php:380
/home/kuba/code/sebastianbergmann/phpunit/src/TextUI/TestRunner.php:64
/home/kuba/code/sebastianbergmann/phpunit/src/TextUI/Application.php:202
--
There was 1 risky test:
1) Test::testSomething
This test did not perform any assertions
/home/kuba/code/sebastianbergmann/phpunit/test.php:20
FAILURES!
Tests: 1, Assertions: 0, Failures: 1, Risky: 1.
Isn't the:
$this->mock->method('get')->with(C1::class)
->willReturn(1);
$this->mock->method('get')->with(C2::class)
->willReturn(2);
incorrect way of mocking method and should be replaced with:
$this->mock->method('get')->willReturnCallback(fn (string $x) => match (true) {
$x === C1::class => 1,
$x === C2::class => 2,
default => throw new LogicException(),
});
I wonder?
Summary
Mocking same method with different "with" and different "return"
Current behavior
How to reproduce
Expected behavior
If "matcher" did not throw an exception on the second "match" (invoke), we should not throw an exception