Search code examples
phpunit-testingdecoratorencapsulation

Intercepting function calls referenced via $this in unit tests


The Scenario

I'm writing unit tests to test an API which is currently in development stages. I have a mock container class (decorator pattern), which contains an array of mocks which will be executed in place of calls to the actual objects.

These mock containers are placed in a DI container during a test run and calls hit the container instead of the model/controllers. In most cases, we allow controllers functions through, but we occasionally want to mock them. The mock container operates by catching inaccessible function calls via __call and either returning assigned mock data or hitting the inner object.

The Problem

This works fine in the usage case of:

$this->c['Controller_Name']->functionHere()

As c['Controller_Name'] is an instance of our mock container, but the problem with this approach comes from a Controller referencing itself via $this->functionHere() when functionHere should be mocked, but the call occurs on $this which is the instance of a Controller and not our Mock Container.

Is there a plausible method for intercepting the calls to a classes own members, so I can catch $this->functionHere() and translate it appropriately into $this->c['Controller_Name']->functionHere()


Solution

  • Without knowing your setup its hard to talk specifics but as you are using Dependency Injection then ensuring that you interface any implementations you wish to exclude from testing will mean that you can create mock versions, mapped using a separate TestDIModule for example. That way you don't need to intercept anything.

    As for catching function calls within an object - I would suggest that if you are needing to do this it may indicate that your class is performing multiple "units" of work thus could be refactored into separate classes and interface them. Extracting these out to interfaces, as described above, would allow these to be mocked and tested independently.