PHPUnit - How to unit test a method with no return value?

When writing unit test for one public function in my class. I was a bit confused about how to test a function which has no return value(s). Normally unit tests validate return of boolean value, arrays or some object. There are parts of code which test of Exceptions being thrown from a function. In this scenario I was not throwing any exception or returning a value. What I wanted to test though if certain functionality was executed or not executed when function was being called.

Example code of a function returning void

class UpdateShipmentTracking
{
    private $tracking;

    /**
     * UpdateShipmentTracking constructor.
     * @param Tracking $tracking
     */
    public function __construct(
        Tracking $tracking
    ) {
        $this->tracking = $tracking;
    }

    /**
     * @param array $orders
     */
    public function send(array $orders): void
    {
        /** @var Order $order */
        foreach ($orders as $order) {
            $this->tracking->track($order->getRealOrderId());
        }
    }
}

// @note this class is being mocked in UpdateShipmentTrackingTest
class Tracking
{
    /**
     * @param string $orderID
     */
    public function track(string $orderID): void
    {
        // add shipment tracking number to order
    }
}

Class UpdateShipmentTracking has the following things

  • 1) It has a constructor injection of class Tracking.
  • 2) It has a function called send which does not return anything. If array is not empty it updates the shipment tracking number.

How can we test a function like this, to be sure that it is functioning properly? If we observe the code properly there are 2 possibilities that can happen when the send function will be called.

Possibility 1
If we pass empty array to the function. Nothing will be executed. The track function of class Tracking will never be called.

Possibility 2
If we pass 1 element in the array. The track function of class Tracking will be called 1 time.

Now that we can see the possibilities. We can test the 2 scenarios. By doing so we cover that the function returning void is properly tested. If you do not believe my statement the screenshot of code coverage will prove that this is indeed true.


class UpdateShipmentTrackingTest extends TestCase
{
    /** @var Tracking */
    private $tracking;

    protected function setUp(): void
    {
        $this->tracking = $this->createMock(Tracking::class);
    }

    public function testEmptyOrdersArrayIsPassedNothingHappens(): void
    {
        // @note we do not expect function track to be called
        $this->tracking->expects($this->never())
            ->method('track');

        $object = $this->getUpdateShipmentTracking();
        $object->send([]);
    }

    public function testShipmentTrackingNumberWasAdded(): void
    {
        // @note we expect track to be called 1 time, since we pass 1 order
        $this->tracking->expects($this->exactly(1))
            ->method('track');

        $order = $this->createMock(Order::class);

        $order->expects($this->exactly(1))
            ->method('getRealOrderId')
            ->willReturn('100001');

        $object = $this->getUpdateShipmentTracking();
        $object->send([$order]);
    }

    /**
     * @return UpdateShipmentTracking
     */
    private function getUpdateShipmentTracking(): UpdateShipmentTracking
    {
        $objectManager = new ObjectManager($this);

        return $objectManager->getObject(UpdateShipmentTracking::class,
            [
                'tracking' => $this->tracking,
            ]);
    }
}

PHPUnit Code Coverage is 100%

PHPUnit code coverage

what clients say about us

Client testimonials

Our sites look great and run smoothly. Thanks for all your hard work and patience in getting us to where we are today.

contact us

Contact Us

If you have questions or want us to send you a quote for project please email us.

latest news

Articles

PHPUnit mock magic functions
Learn more about PHPUnit Partial Mock.