phpunit icon indicating copy to clipboard operation
phpunit copied to clipboard

Mocking same method with different "with" and different "return" throw an exception

Open oleg-andreyev opened this issue 5 years ago • 5 comments

Q A
PHPUnit version 9.2.6
PHP version 7.4.8
Installation Method Composer

Summary

Mocking same method with different "with" and different "return"

Current behavior

Expectation failed for method name is "getRepository" when invoked zero or more times
Parameter 0 for invocation Doctrine\ORM\EntityManager::getRepository('Op\AppBundle\Entity\Order') does not match expected value.
Failed asserting that two strings are equal.
Expected :'Op\AppBundle\Entity\Customer'
Actual   :'Op\AppBundle\Entity\Order'

How to reproduce

        $this->em
            ->method('getRepository')
            ->with(Customer::class)
            ->willReturn($this->customerRepository);

        $this->em
            ->method('getRepository')
            ->with(Order::class)
            ->willReturn($this->orderRepository);
$this->em->getRepository(Order::class)->findOneByOrderId($id);

image

Expected behavior

If "matcher" did not throw an exception on the second "match" (invoke), we should not throw an exception

oleg-andreyev avatar Aug 05 '20 13:08 oleg-andreyev

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 avatar Dec 28 '20 06:12 sebastianbergmann

@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. 

emdadulsadik avatar Mar 06 '23 19:03 emdadulsadik

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. 💪👍

oleg-andreyev avatar Mar 06 '23 23:03 oleg-andreyev

Sorry, but something that uses Doctrine's entity manager is neither minimal nor self-contained.

sebastianbergmann avatar Mar 07 '23 05:03 sebastianbergmann