Intercepting function calls referenced via $this in unit tests - php

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()

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.

Related

Laravel - difference between singleton and instance binding in service container

In the service container of Laravel, I can bind both singleton and instance. From the Laravel doc:
Binding A Singleton
The singleton method binds a class or interface into the container that should only be resolved one time. Once a singleton binding is resolved, the same object instance will be returned on subsequent calls into the container:
$this->app->singleton('HelpSpot\API', function ($app) {
return new HelpSpot\API($app->make('HttpClient'));
});
Binding Instances
You may also bind an existing object instance into the container using the instance method. The given instance will always be returned on subsequent calls into the container:
$api = new HelpSpot\API(new HttpClient);
$this->app->instance('HelpSpot\API', $api);
Q1) So what is the difference between the two concepts? Can I guess that for singleton binding, Laravel upon first request builds the object itself through internal service container mechanism and then supplies it on subsequent calls whereas in the case of instance binding, service container is explicitly given an already built object which it supplies on every request?
Or is there any other explanation?
Q2) Why do we need both binding options?
Difference between singleton and instance
The two concepts are very much alike. The only difference is, indeed, the fact that you either pass in a class/interface or an object.
Singleton docs:
The singleton method binds a class or interface into the container that should only be resolved one time. Once a singleton binding is resolved, the same object instance will be returned on subsequent calls into the container
Instance docs
You may also bind an existing object instance into the container using the instance method. The given instance will always be returned on subsequent calls into the container
Why do we need both?
The answer to this question is probably rooted in the Laravel philosophy. From what I see in most of the features Laravel provides, there's more than one way to solve an issue. It feels like this is one of those as well. There's slight differences which might make singleton or instance usage preferable in some cases.
Singleton usage
The use of singleton will help keep your application light, as these classes/interfaces do not get created if they are not used.
Instance usage
In some cases you might've already created an object, which you still need to inject into other places. That's where instances comes in.
Additional to what #PtrTon said, the difference is also in the time, the instance is created. Using an instance, the instance is—of course— created before passing to the service container, meaning it's created quite early. Whereas using a singleton, the instance is created the first time, the binding is resolved as far as I know which can be a considerable amount of time after the example where you pass an instance.

Making a PHP method throw an exception in a test

I have an AuthorizationUpdater service, with an implementation based on Doctrine ORM. While I finished the production code, and have some tests, I was forced out of my usual TDD cycle by not knowing how to write these two:
testWhenDatabaseReadFails_exceptionIsThrown (to test this code)
testWhenDatabaseWriteFails_exceptionIsThrown (to test this code)
The Doctrine implementation of AuthorizationUpdater take a Doctine EntityManager in its constructor, which it uses to do a read and a write. These two tests are supposed to test that when either of these EntityManager methods throws a Doctine ORMException, it is caught by the service and converted to a domain exception.
My test is an integration test that gets the EntityManager to use from a factory.
Creating a simple fake via the PHPUnit mock API (getMock('className')->method('updateStuff')->willThrow(new SomeExcetion)) does not seem nice in this case. The service uses the EntityManager before the method the exception gets thrown from, so mocking out everything is not an option. This leaves creating some complex fake of EntityManager and partially mocking it (just the method that should throw an exception). The later requires providing the real constructor arguments, which my test actually does not have access to, as this responsibility lies in another package. Hence both approach are not satisfactory, and leave me preferring to have this ORMException catching behaviour to be not tested.
Is there a nice way to write the tests I'm after? Being able to monkey-patch the relevant method on the EntityManager instance would be prefect, though that'd require the runkit extension.
I'm using PHP 7, and might be able to switch to PHP 7.1 if needed.In case you're curious, the code is on GitHub, with the relevant tests residing at the end of DoctrineAuthorizationUpdaterTest.
Instead of creating a mock object through the PHPUnit mock API you could create a proxy class in your test namespace, that gets the EntityManager from the factory as constructor parameter. The proxy class passes every method call to the EntityManager, except for the calls that are to throw an exception. Most calls could be passed through with the __call magic method, except for the calls to interface methods of Doctrine\Common\Persistence\ObjectManager, which the Proxy class will probably have to implement (interface methods can't be implemented with call).
Is this proxy class the "complex fake" you are talking about and want to avoid? Then maybe you can use the Mockery library and don't have to write the class.

IoC Container and global variable

I see advise from a lot of people teach not to use global variable/singleton/static class and move to use of a iOC container, for example, in PHP larvel framework, it is
App::bind('foo', function($app)
{
return new FooBar;
});
$value = App::make('foo');
instead of
$value = new FooBar;
But to me, the App::bind itself is a static method and cannot be replaced easily.
So, can I say, the iOC (at least in PHP), is just remove the number of hard coded variable and minimized to one, which is the service locator, and it cannot be further reduced, right?
App::bind is not a static method, this is it's signature:
public function bind($abstract, $concrete = null, $shared = false)
(found in /vendor/laravel/framework/src/Illuminate/Container/Container.php)
Laravel uses Facades, which, while they look like they are calling a method statically, actually instantiate an object under the hood and then call an instance method on that object. While Laravel does use some static methods in it's models, the App object itself is actually a facade. You can see a list of the built in facades if you look in /vendor/laravel/framework/src/Illuminate/Support/Facades/.
So, can I say, the iOC (at least in PHP), is just remove the number of hard coded variable and minimized to one, which is the service locator, and it cannot be further reduced, right?
You are seeing this correctly, but you can actually reduce the number of hard coded variable to 0.
The problem here is not App::bind() because it's configuration. Configuration has to be coupled to some kind of system because that's where you set all the details. That's OK here.
But having App::make() all over your codebase is the problem. You want to write reusable code. You don't want your model to be coupled to Laravel for example. The fact of calling the container is called the service locator pattern (because you locate services with the IoC).
This is an anti-pattern, because, as I've said, you are coupling your code to the container.
On the other hand, there is the dependency injection pattern which is better. Dependencies are injected in your classes, but you don't care how. This is just pure PHP, completely decoupled from any container.
I invite you to read stuff on the subject, Laravel can actually be used with full dependency injection (no static calls to Facades). Here is an article on the subject: Using Dependency Injection and IoC in Laravel 4 controllers
Howard, I think the context you might be missing is why people say
global variable/singleton/static class
are "bad". The reasons you don't want global variables in your application is, relying on global state is going to lead to pain. When you're modifying values that other parts of the program also have access to, it's likely two parts of a program are going to access that same variable and unexpected "bad" things will happen. Singletons and static classes are often lumped in with global state, because they're globally available things.
So yes, your statment
is just remove the number of hard coded variable and minimized to one, which is the service locator, and it cannot be further reduced, right
is accurate, but more than that a service container (if services are being created correctly) gives you global access to a thing-to-do-a-job, but is makes it hard/impossible to use that global thing-that-does-a-job to store global application state.

Unit Testing (PHP): When to fake/mock dependencies and when not to

is it better to fake dependencies (for example Doctrine) for unit-tests or to use the real ones?
In a unit test, you use only ONE real instance of a class, and that is the class that you want to test.
ALL dependencies of that class should be mocked, unless there is a reason not to.
Reasons not to mock would be if data objects are being used that have no dependencies itself - you can use the real object and test if it received correct data afterwards.
Another reason not to mock would be if the configuration of the mock is too complicated - in that case, you have a reason to refactor the code instead, because if mocking a class is too complicated, the API of that class might be too complicated, too.
But the general answer: You want to always mock every dependency, every time.
I'll give you an example for the "too-complicated-so-refactor" case.
I was using a "Zend_Session_Namespace" object for internal data storage of a model. That instance got injected into the model, so mocking was not an issue.
But the internal implementation of the real "Namespace" class made me mock all the calls to __set and __get in the correct order of how they were used in the model. And that sucked. Because every time I decided to reorder the reading and writing of a value in my code, I had to change the mocking in the tests, although nothing was broken. Refactoring in the code should not lead to broken tests or force you to change them.
The refactoring added a new object that separates the "Zend_Session_Namespace" from the model. I created an object that extends "ArrayObject" and contains the "Namespace". On creation, all the values got read from the Namespace and added to the ArrayObject, and on every write, the value also gets passed to the Namespace object as well.
I now had the situation that I could use a real extended ArrayObject for all my tests, which in itself only needed an unconfigured mocked instance of "Zend_Session_Namespace", because I did not need to test whether the values were correctly stored in the session when I tested the model. I only needed a data store that gets used inside the model.
To test that the session gets correctly read and written, I have tests for that ArrayObject itself.
So in the end I am using a real instance of the model, and a real instance of the data store together with a mocked instance of "Zend_Session_Namespace" which does nothing. I deliberately chose to separate "model stuff" and "session save stuff" which had been mixed into the model class before -> "single responsibility principle".
The testing really got easier that way. And I'd say that this is also a code smell: If creating and configuring the mock classes is complicated, or needs a lot of changes when you change the tested class, it is time to think about refactoring. There is something wrong there.
Mocking should be done for a reason. Good reasons are:
You can not easily make the depended-on-component (DOC) behave as intended for your tests.
Does calling the DOC cause any non-derministic behaviour (date/time, randomness, network connections)?
The test setup is overly complex and/or maintenance intensive (like, need for external files)
The original DOC brings portability problems for your test code.
Does using the original DOC cause unnacceptably long build / execution times?
Has the DOC stability (maturity) issues that make the tests unreliable, or, worse, is the DOC not even available yet?
For example, you (typically) don't mock standard library math functions like sin or cos, because they don't have any of the abovementioned problems.
Why is it recommendable to avoid mocking where unnecessary?
For one thing, mocking increases test complexity.
Secondly, mocking makes your tests dependent on the inner workings of your code, namely on how the code interacts with the DOCs. Would be acceptable for white box tests where the implemented algorithm is tested, but not desirable for black box tests.

How to test and mock zend framework controllers with PHPUnit?

Im trying to unit test my controllers, but every tutorial I found on the internet says that I should use $this->dispatch("controller/action") to run the specific action I want to test. But doing it like that, I can't mock anything like data mappers, or other calls to other methods.
To solve this, I was trying to get an instance of the controller class, and then calling directly to the methods I wanted to test, but doing it like this, I get an error:
Zend_Exception: Setting request object manually is not allowed
Im not even sure this is the right approach, because I dont really know how I will test things doing it like this.
My test case: http://pastie.org/1812717
My ControllerTestCase: http://pastie.org/1812722
Any help would be appreciated.
Thank you.
You have two solutions:
Pseudo unit testing (more like acceptance testing) with Zend_Test_PHPUnit_ControllerTestCase
Creating new instance of the Controller, passing all the required dependencies (dispatcher, request, response, plugin managers etc.)
Both of them actually require dispatching process. The first, dispatching the application, second, dispatching the controllers.
See the manual and sample tests from the full Zend Framework package.
Also, look at the controller source code, to see, how the dependencies are managed.
See also other SO posts about Dependency Injection to the Zend Framework controllers.
I would guess that Zend_Test_PHPUnit_ControllerTestCase is preventing you from being able to mock Requset and Response objects. I would bypass it and just extend PHPUnit_Framework_TestCase. As I mentioned in another question, I am currently mocking Controllers without any problems.
Here is an example test that runs fine:
http://pastie.org/1816705
AbstractRestController is simply a controller class that extends Zend_Controller_Action
How is your data mapper (or other objects) instantiated? Are you instantiating it directly in the controller or grabbing it from the bootstrap/registry? If using registry or bootstrap, then place the mock in the registry/bootstrap.
If you are directly instantiating in the controller, you will need to modify your controller. Maybe have a controller method to set the data mapper, and then have another method to grab the data mapper, and if one is not set, then instantiate it. That allows your tests to inject a mock.
I typically don't mock many classes when testing controllers - I want to test the entire app and its ability to render the page... It looks like you are testing no records in the database, so why not use Zend_Test_PHPUnit_Db to set up an empty table for that test, rather than mock the data mapper to return no data?

Categories