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.
Related
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.
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.
What are the main differences, in term of performance between service, controller as a service or using a sort of auxiliary object to do the job?
more precisely for this scenario/use-case:
i've got an API on mysite/api, my question is:
Is it better to define a controller as service, a service itself or using in "classical way" as a controller doing all the job with at least an auxiliary object (as a mini-lib) to do most of the job?
auxiliary object I mean use an istance of a class, i suppose everytime the api is called, create the new object (not so good for performance I think).
thanks in advice for your answers.
There won't be any significant performance differences, and all three approaches are absolutely valid, it just matters on your use case.
Thing to note: Controllers are basically services, they are just container aware by default in Symfony (making them Service Locators). It doesn't matter whether controller is a Service, a ContainerAwareInterface object or some object you made, it has to be instantiated either way.
That said, controller is just one of probably hundreds (if not thousands) of objects that will be created on each request and time needed to instantiate it is really negligible.
Use whatever method suits you best.
Edit
Hell, symfony controllers aren't even ContainerAware by default, they are just made so in their examples since they always extendsSymfony\Bundle\FrameworkBundle\Controller\Controller. You can try to make a Controller class like so:
<?php
namespace MyVendor\MyBundle\Controller;
class MyCustomController
{
public function myAction()
{
// do your thing here
}
}
And it will work just fine.
Here is the Symfony code that instantiates controller: ControllerResolver::createController
Basically, it checks whether string matches 'Bundle' pattern or 'Service' pattern. If neither, it just treats it as 'ClassName::methodName', and one way or another: instantiates it.
There is no difference which approach to use. But there are a lot of another questions - rest api routing, formats, documentation etc.
Use ready solution for rest-api gimler/symfony-rest-edition
I have a class I call my Dispatcher and when its dispatch() method is run it instantiates the requested controller.
My AbstractController has a constructor like
public function __construct(RequestInterface $request, ResponseInterface $response, ViewFactory $viewFactory, ServiceFactory $serviceFactory)
As you can see my controllers have 4 dependencies.
At the moment when I instantiate my Dispatcher I inject the ViewFactory and ServiceFactory into its constructor and then when I run the dispatch() method I supply the Request and Response objects as arguments and I can then inject all four dependencies into my controller.
Would it be better to just supply all the controllers dependencies when calling the dispatch() method or supply them all in the constructor of the Dispatcher and then run a dispatch() method with no arguments or is there a better way overall?
You have 4 dependencies you want to inject in a new controller instance, 2 have a request/response life cycle and 2 have a longer life cycle (process?), before invoking some method on it. I would separate the creation of the controller from the invoking by creating a controller factory.
The controller factory would instantiate a controller using a method that receives only the request and reponse objects as parameters. The factory would be aware of the life cycle of the two longer lifed dependencies, perhaps share the same life cycle. The factory's user is then free to invoke any method they would like on the (abstract) controller returned. This is more flexible than the delegation pattern you propose. You could of course still use delegation, but then I would probably still have the Dispatcher only do dispatching and leave object creation to a factory.
Of course, there is no right answer with these kind of questions. It all depends on a lot of factors (requirements, size of codebase, the project, etc). Hope this helps though. Good luck!
Some "blah"
Here is a rule of thumb that I use when design API: if your class has 3+ dependencies, it is doing too much.
The dependencies that you pass in the constructor, should be mandatory for your instance to function. In your case, you have a controller there. Controllers repsonsibilities are as follows:
A controller can send commands to its associated view to change the view's presentation of the model. It can also send commands to the model to update the model's state.
source: wikipedia
Controllers should not be responsible for creation or rendering of the view instance.
Regarding the original question:
I am not sure what is the role of the Dispatcher instances, but they should not be dealing with creation logic itself. What you essentially end up with here is a mix of possible LoD violation and a definite SRP violation.
The creation logic should be segregate to factories and builders. This way would also let you decouple your Dispatcher instances from the footprint of controller's constructor. Currently, if you introduced a different subclass of controllers, with different set of dependencies, you would also need to change the Dispatcher implementation.
As for "how to make a factory", you can find a simplified example here.
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?