Symfony2 Functional Testing: Is a database required or not? - php

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.

Related

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.

Have access to a common class in a PHP MVC framework

I have read a lot of SO topics about this already, but still haven't found (or have been able to create) a proper answer.
I am working on a small MVC framework and I want some global class/object that I can call from my controllers (but maybe models too).
There are a couple of routes I can take:
Global variable
Static class/Registry
Dependency injection
The internet seems to agree that the DI is the best route to take. I think I have grasped the idea, but am not comfortable yet. So I want to throw in some background information; I will probably be the only one working on the project, it is a small project, all my controllers extend the main Controller (so I could just load one library like class there).
As a concrete example, I want to have an array of categories. So I started out with putting that array in the CategoryController. But now I noticed I kinda want to use that array in my frontview and in ProductController as well. Obviously I don't want to load all of CategoryController into ProductController.
You could also say I could put that array in some kind of configuration or settings file, because of the simpleness of this example, but that's why it's an example. I will probably expand on it with more functionality.
So to summarize: In PHP (specifically inside a MVC model) how can you give your classes (mainly Controllers) access to some kind of common class or other sharable functionality.
Your controllers are created by "something" (usually a front controller). So when the controller is created, you could inject a dependency injection container.
And in your configuration/bootstrap (before the controller is created), you should add you categories to the container.
That way you can access the categories from every controller.
Please note that this is a simple example that doesn't totally fit the spirit of dependency injection. The best solution would be to inject directly the categories (instead of injecting the container). But that can become a lot of work if you generalize that pattern (lots of dependencies to handle in your front controller).
A solution would be to use a dependency injection framework that could do that for you.
For example I work on a DI container that lets you inject stuff with annotations (PHP-DI), but there are several other libraries for DI so you have a choice.
My 2 cents:
In a small self-made mini-framework I have done some time ago, I have created a global singleton class named Application, and anything/everything which should be accessible from anywhere/everywhere was a property or method of this class.
In my case, there was a $db property for database access, a $user property to access the user data and methods, an $input property for a "powered" $_REQUEST access, and so on.
Of course, you have many other options, suitable for different scenarios. This approach simply worked fine for me on that occasion.
Now, if you want to access a controller from another controller, this really sounds strange. This "thing" that you want to access should be a model class, a library class, or anything else, but it should not be "locked" inside a controller class. Indeed, the controller should be "as thin as possible", and focus on calling the appropriated methods from other classes, based on the user input (request) and then calling some output method to generate and send the answer (response).
Finally, although I've read some criticism and complaints about it (as well as praises too), I do make use of static methods a lot, mainly for classes which are more "helpers" than anything else.

Writing mocks/stubs for an object before you have written the class for that object?

I'm designing a class that has two dependencies. One of the dependency classes has been written and tested. The other has not yet been written.
It has occurred to me because the remaining dependency will be written to facilitate the class that will use it, that I should write the latter first, and design the interface of the former as I go along, learning what it should do.
That seems to me to be a great way to make code. After all, as long as the main class gets a mock in its constructor, I can write it and test it without it being aware that its dependency doesn't exists, then I can create the dependency once I am sure I know what I need.
So: how do I do this? Create a skeleton class that I modify as I go along. Perhaps something like:
class NonExistantSkeleton
{
public function requiredMethod1()
{
}
public function newlyDiscoveredRequirement()
{
}
}
and then mock it using PHPUnit, and setting up stubs, etc, to keep my class under development happy?
Is this the way to go?
It seems like a nice way to develop code - and seems to me to make more sense than developing a dependency, without really knowing for sure how it's going to be used.
In short:
Yes. At least thats what I'm doing right now.
Longer Version:
If the expected collaborators of your class don't exist at the point in time where you need them in your tests for the class you are building you have a few options:
Mock non existing classes (which phpunit can do)
Create class skeletions and mock those
Just create interfaces and get mocks for those (which phpunit can do too)
Maybe you don't need any of the above depending on the object
If you programm against an interface anyways than all you need to do is to create that interface and tell PHPUnit to create a stub/mock from it
+No new class without a test
+Using interfaces when appropriate is considered nicer/better than just hinting against classes
When mocking non existing classes you get some drawbacks that I don't like:
-High mock maintenance cost
-Chaning the methods on that classes is slow and tedious
-If you created the class you should rework the mocks again
so I'd advice against that.
The middle way would be to just create the empty class skeleton with its method and use those for mocking.
I quite like that way in cases where there is no interface to hint against as It is fast and creates stable test code.
Having barebone classes with public apis, for me, is no violation of TDD.
There are classes you don't need to mock.
Data transfer objects and Value Objects can always be created anywhere using the new in your production code so your tests also can just the the real objects.
It helps to keep your tests a little cleaner as you don't need to mock/expect a lot of getter/setter methods and so on.
If you follow a test-driven development methodology then the usual approach is as follows:
Figure out what your classes are meant to do, and what their public-facing APIs should be.
Implement "empty" classes that consist of nothing but the public methods signitures with empty bodies (as you have done in the code example you gave).
Work out an implementation strategy. This means working out which classes are dependant on each other and implementing them in an order that means that dependant classes aren't implemented until the classes it depends on are finished, or at least sufficiently functional to develop against. This means doing the classes with no dependencies first, then the classes that depend only on the completed classes, and so on.
Write your tests. It's possible to write the tests now because you know what the black box for your classes look like, what they need to take as input and what they're supposed to return as output.
Run the tests. You should get 0% success, but also 100% code coverage. This is now your baseline.
Start to implement your classes according to your implementation strategy. Run your unit tests from time to time during this process, say once you've got a class completed, to make sure that it meets its specification as laid down in the unit test. Ideally, each test should show an increase in test passes whilst maintaining 100% code coverage.
EDIT: As edorian pointed out, PHP interfaces are a huge help here because PHPUnit can generate mocks and stubs from interfaces as well as from classes. They're also an excellent tool in reducing coupling and improving substitutability in general. They allow you to substitute any class that implements the expected interface, instead of just subclasses of the expected class.

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