PHPUnit тестирование с закрытием

Это появилось, пытаясь написать тест для метода класса, который вызывает макет с закрытием. Как бы вы подтвердили, что закрытие называется?

Я знаю, что вы сможете утверждать, что параметр является экземпляром Closure . Но как бы вы могли проверить что-нибудь о закрытии?

Например, как бы вы проверили переданную функцию:

  class SUT { public function foo($bar) { $someFunction = function() { echo "I am an anonymous function"; }; $bar->baz($someFunction); } } class SUTTest extends PHPUnit_Framework_TestCase { public function testFoo() { $mockBar = $this->getMockBuilder('Bar') ->setMethods(array('baz')) ->getMock(); $mockBar->expects($this->once()) ->method('baz') ->with( /** WHAT WOULD I ASSERT HERE? **/); $sut = new SUT(); $sut->foo($mockBar); } } 

Вы не можете сравнить два закрытия в PHP. Есть ли способ в PHPUnit выполнить параметр, переданный или каким-то образом проверить его?

Solutions Collecting From Web of "PHPUnit тестирование с закрытием"

Ваша проблема заключается в том, что вы не вводите свою зависимость (закрытие), которая всегда усложняет модульное тестирование и делает невозможным изоляцию.

Внесите закрытие в SUT::foo() а не создавайте его внутри, и вы обнаружите, что тестирование намного проще.

Вот как я бы разработал метод (имея в виду, что я ничего не знаю о вашем реальном коде, поэтому это может быть или не быть практичным для вас):

 class SUT { public function foo($bar, $someFunction) { $bar->baz($someFunction); } } class SUTTest extends PHPUnit_Framework_TestCase { public function testFoo() { $someFunction = function() {}; $mockBar = $this->getMockBuilder('Bar') ->setMethods(array('baz')) ->getMock(); $mockBar->expects($this->once()) ->method('baz') ->with($someFunction); $sut = new SUT(); $sut->foo($mockBar, $someFunction); } } 

Если у закрытия есть некоторые побочные эффекты внутри SUT которые могут быть проверены тестом после макетного вызова, используйте returnCallback чтобы предоставить другое замыкание, которое нужно вызвать с переданными аргументами, и вернуть его возвращаемое значение в SUT . Это позволит вам вызвать закрытие SUT , чтобы вызвать побочные эффекты.

  class SUT { public function foo($bar) { $someFunction = function() { return 5 * 3; }; return $bar->baz($someFunction); } } class SUTTest extends PHPUnit_Framework_TestCase { public function testFoo() { $mockBar = $this->getMockBuilder('Bar') ->setMethods(array('baz')) ->getMock(); $mockBar->expects($this->once()) ->method('baz') ->will($this->returnCallback(function ($someFunction) { return $someFunction(); })); $sut = new SUT(); self::assertEquals(15, $sut->foo($mockBar)); } } 

Если вы хотите __invoke анонимную функцию (обратный вызов), вы можете __invoke класс с __invoke метода __invoke . Например:

 $shouldBeCalled = $this->getMock(\stdClass::class, ['__invoke']); $shouldBeCalled->expects($this->once()) ->method('__invoke'); $someServiceYouAreTesting->testedMethod($shouldBeCalled); 

Если вы используете последний PHPUnit, вам придется использовать mock builder, чтобы сделать трюк:

 $shouldBeCalled = $this->getMockBuilder(\stdClass::class) ->setMethods(['__invoke']) ->getMock() $shouldBeCalled->expects($this->once()) ->method('__invoke'); $someServiceYouAreTesting->testedMethod($shouldBeCalled); 

Вы также можете установить ожидания для аргументов метода или установить возвращаемое значение, точно так же, как и для любого другого метода:

 $shouldBeCalled->expects($this->once()) ->method('__invoke') ->with($this->equalTo(5)) ->willReturn(15);