How to test and mock zend framework controllers with PHPUnit? - php

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?

Related

How to test a controller that communicate with a microservice?

I have the next scenario: I have to write some unit testings for controllers. In the controllers i have all types of CRUD actions. The problem is that in actions of post/patch/delete my api is communicating with a web service where i pass some data. The communication is done with guzzle.
Question: How to avoid the communication when i call a route? Is there other possibility to test the hall controller?
I assume that your microservice is a class which is registered in the Laravel's service container.
As far as I know, you can't mock classes outside the container in Laravel.
So, In case you're not doing that, register the service in the container in AppServiceProvider class. And get the microservice from the container in the controller See here for details.
In your unit test, you can make a mock object of your microservice according to your needs and inject it in the container (replacing the real one). for eg.
$this->instance(MyMicroService::class, Mockery::mock(MyMicroService::class, function ($mock) {
// here you tell the mock object which method will be called and what to return and how many times it will be called. it's totally customizable.
$mock->shouldReceive('contactRemoteServer')->once()->andReturnTrue();
}));
and it's easier if you use the mock method in your testcase class, but it does the same thing:
$this->mock(MyMicroService::class, function ($mock) {
$mock->shouldReceive('contactRemoteServer')->once()->andReturnTrue();
});
see the docs for more examples.
NB: In case you don't know, A mock class is a class made especially for the test so it doesn't affect the results and to be controllable in accordance to the test needs.
For example if you want to have a case where your microservice will throw an exception and you want to test the controller's response for that you will have to create a mock class for each unit test.
Create a sample class with the same functionality but I have one question if you are creating unit tests and you don't want to make the guzzle work so what will you test.
Please read the documentation carefully you will get the option.
In my suggestion, you can use mocking.

Symfony2 Functional Testing: Is a database required or not?

I have to write functional tests for a controller that registers a user in the application.
The controller has two methods (and routes):
registrationAction (route=registration)
endAction (route=registration/end)
Now I would like to write functional tests for those two methods.
My question is: as the controller creates and persists a new user in the database, should have I to use a test database? Is the mocking of entity manager a solution? And how can I test that the user is correctly created in the database?
The Symfony's documentation, speaking about functional testing of forms, don't mention database, but generally the filling of the form and the submit of it. But if i try to do the same thing in my functional tests, they return errors (and I think they are right: there is no database where to save submitted data!).
So, I think I should use a database for functional tests, but I don't understand why:
Symfony's documentation doen't mention the database
Someone suggests to use mocks of the Entity Manager.
I'm a bit confused: should have I to use a database or not?
Answer to this question in not simple yes/no, you can do it in both ways, both have its advantages and disadvantages.
1. With test database
You mention that you need to write controller test. Testing controller is testing of almost top layer of your application flow. Controller depends on many class implementations which you would need to mock if you would like to test your controllers logic with isolation. If your controller has it's dependencies injected into contructor using service container I would possibly think of mocking but if it extends Symfony's Controller I would use test database mocking everything in this case would be harsh.
2. Without database
In this case you need to mock your entity manager and this is possible. However in your case I would think of refactoring. Move logic outside your controller to some UserManager or similar class. Register this class as a service and inject all required dependencies. Think of injecting repository instead of whole EntityManager as described here. Now, because your code is more single responsible it's easier to write tests and it's easier to mock all of your dependencies.
Conclusion: do refactoring, move your logic outside of controller, write test for single responsible class by injecting mocks of dependencies into it.

Unable to mock Model::where() and prevent test from querying database

In my controller I'm using MyModel::where(...) which is calling the database during one of my tests. I thought that I'd be able to overload it with the following but it's still querying the database. What can I do to be sure my test is still requiring that ::where is called but returns a mocked model so I can resume testing the rest of this controller method?
MyModel::shouldReceive('where')
->once()
->with('param1', 'param2')
->andReturn($mockedModel);
First of all, you have to understand why you can't mock the where method. That's because the class Illuminate\Database\Eloquent\Model (Eloquent is its alias) doesn't have a where method explicitly declared. This method is called through the magic methods __callStatic and __call and is, in fact, a method of Illuminate\Database\Eloquent\Builder (sources).
Then, you have several options :
You can accept to call your database in your tests and just define a real context before your assertions. Your tests will be less unitary but we can deal with that in most of the cases.
#michaelcurry solution is a good one. You can build your own abstraction layer with query scopes or other architecture (injecting the query builder by yourself in the model for example) to produce a more testable code.
[never tried] You can mock directly the DB facade to completely bypass the database. You will need a good understanding of the Laravel core but it could be a good way to write "pure" unit tests.
Anyway, don't hesitate to dive into the Laravel source code. The code is clear and there are just few classes really important. That's essential to really exploit the power of the framework.
Use http://laravel.com/docs/eloquent#query-scopes and create a new function that just returns the data you want.
If you have not read it "Laravel: From Apprentice To Artisan" I would suggest it. Will help you understand how all of this is structured.

Correct way to log from Entities and Repositories in Symfony2

What is a way to log messages or errors from an Entity or Repository class in the symfony2 architecture? In symfony1 you could use the singleton to kill puppies by doing something like this to get the logger from anywhere:
sfContext::getInstance()->getLogger()
Symfony2's container model is stricter, which is great, but how should one go about logging from non-container-aware classes? For repos, I guess you can define them (all) as services, with a dependency on the logger, and go from there. But what about when you just have an instance of an Entity class?
Historically I'd want to put the log message inside class methods, but now? Should I pass the logger (as a parameter) into every class method that wants to write a log message? This seems like a bit of overkill but perhaps it's best practice?
Or am I looking at this wrong and Entities or Repos shouldn't be writing log messages but passing them back to the controller to handle?
You should probably avoid putting business logic (even logging) inside entity model.
As for the repositories, the way you described is the right one.

CakePHP: Where to put 'Services' logic

I come from a Java/Grails background and cannot seem to find a definite answer online as to where the service logic for a CakePHP application should be stored. By "Services", I am talking about classes that are usually instantiated through dependency injection to conduct business logic on domain objects. They should be able to query any domain object and make changes in response to a controller action.
Currently, CakePHP's "Component" class seems to be the closest match to this behavior. I can load a component into any controller and execute its methods as needed. However, I have read in several places that components should never access the database and that doing so will result in some steep performance hits.
I have also looked into CakePHP's "Behavior" class and it doesn't seem to fit the ticket at all. It seems well-equipped to organize domain objects into a data structure setting, but that's not the kind of logic that a service would execute. Also, to import any model definition into a Behavior, I would have to edit the model definition itself to allow access, which is very awkward.
So I ask this question: Where should service logic be stored? Certainly not the controller, as it should only contain the minimal logic to process a request and send a response.
Components are the service layer in CakePHP. They are constructed by a dependency injection container (Components Collection) and get passed the controller, request and response that is to be handled.
There are no restrictions in what Components can do other than maintaining separation between layers. It is fine to use database connections, or use models, directly from a component and modify the request.
Components are actually very light-weighted if you only make them act for specific cases. Inspecting the action name, is a common way of limiting the reach of a component. You can also inject setting so it can know when is OK to execute custom service logic.
So I ask this question: Where should service logic be stored?
Certainly not the controller, as it should only contain the minimal
logic to process a request and send a response.
Sounds like the ideal use case for a Dispatcher Filter. It gets called even before a controller is instantiated. If you need to query the database simply load a model via ClassRegistry::init('YourModelName') and pass the request params to the model method and return whatever you need in your request. No controller needed at all. We've implemented oauth + xhttp using Dispatcher Filters without calling ever a controller.
How using a model inside a component should effect the performance... I don't know who got that strange idea, sounds like not the best article you found. It is true that you should not put model layer related logic in them but you can call a model for example through the controller instance and the controllers models.

Categories