Qafoo GmbH - passion for software quality ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :Author: Benjamin Eberlei :Date: Tue, 08 Mar 2016 10:33:33 +0100 :Revision: 4 :Copyright: All rights reserved ================================================= Testing Effects of Commands With Phake::capture() ================================================= :Abstract: Today I want to share a simple trick for the excellent Mocking library Phake (`I wrote about it before `_) when testing state on APIs that don't return values. :Keywords: testing, mocking, phake Today I want to share a simple trick for the excellent Mocking library `Phake `_ (`I wrote about it before `_) when testing state on APIs that don't return values. Testing becomes harder when you are using command / query separation in your code and service operations don't return values anymore. If your command method creates objects and passes them down the stack, then you usually want to make assertions on the nature of the changes. Take the following example that creates a new ``Order`` object:: orderRepository = $orderRepository; $this->productRepository = $productRepository; } public function checkout(Checkout $command) { $order = new Order(); $order->setAddress($command->address); foreach ($command->productIds as $id => $amount) { $product = $this->productRepository->find($id); $order->addItem($product, $amount); } $this->orderRepository->save($order); } } A "usual" PHPUnit test for this class can only make a single assertion that the ``OrderRepository`` is called with an ``Order`` object. But we might want know if a product was correctly assigned. .. note:: We can help you to set up continuous and automated testing for your projects. Book a `workshop`__ now. __ /services/workshops/testing.html With ``Phake::capture($value)`` we can assign the argument passed to ``OrderRepository#save($order)`` to a variable that is available inside the Unit-Test, ready to run assertions on. :: find(42)->thenReturn($product); $handler = new CheckoutHandler($orderRepository, $productRepository); $handler->checkout(new Checkout([ 'productIds' => [42 => 1], 'address' => new Address(), ])); \Phake::verify($orderRepository)->save(\Phake::capture($order)); $this->assertEquals(1, count($order->getProducts())); $this->assertSame($product, $order->getProducts()[0]); } } See after the ``\Phake::capture($order)`` call, the ``$order`` variable contains the argument that was passed to the OrderRepository from your code. This argueably reaches into the tested class quite a bit, but when you use Command / Query separation and London-Style TDD the only way to observe behaviour and state is mocking. I still think Phake is the best mocking library for PHP and the capture method is another good argument for it. .. Local Variables: mode: rst fill-column: 79 End: vim: et syn=rst tw=79 Trackbacks ========== Comments ======== - Bart at Tue, 12 Apr 2016 21:11:41 +0200 Very nice article. thx