PHPUnit and testing CRUD methods - php

I've got PHP DAO classes with CRUD methods (inserting, reading, updating, and deleting DB records). In many of PHPUnit testing examples on internet there's a test with simple sum($a,$b) method where one can easily define input and expected output for PHPUnit testing (1+1 should return 2).
How to test CRUD methods? Sometimes I change database model, sometimes I do refactor/change my code. My question here is how to define assertions for insert, select, update, and delete methods of my class? I want to test with PHPUnit weather my CRUD methods work as expected?

I use this for my database tests (when mocking does not do the trick - at some point you want to actually test the database interaction) - https://github.com/malteriesch/test-db-acle
An alternative (quite popular one) is DBUnit: https://github.com/sebastianbergmann/dbunit
Disclaimer: I wrote test-db-acle so I tend to gravitate towards that one :)

Related

Set order of test execution in a single class for Symfony WebTestCase (PHPUnit)

I'm adding test coverage to an API built in Symfony. I have an ApiControllerTest that is extending Symfony's WebTestCase, and performs tests on the different controller actions of the API controller. Please note these are functional tests so they are calling controller routes and and saving to the database.
I want the tests to run in a specific order. For example, there are API methods to save a project, match that project to another, add a requirement to that project, delete that project, etc. I understand that unit tests should not depend on each other, but it seems functional tests can. Instead of having set up and tear down methods that manually add / delete a project before and after every test, it would be much more efficient to save a project in the first test, then have subsequent tests update, delete, etc. for that project.
I have looked at Run PHPUnit Tests in Certain Order and tried using the #depends annotation, but this does not work (I'm not trying to pass the result of one test to another). Also, I've seen that you can specify the order for separate classes to run, but it seems like these tests are all related and belong in a single class, as they are testing a single controller (I typically have one test class per controller class, service class, etc. that I'm testing)
Is there a way using PHPUnit or Symfony's WebTestCase to specify the order that tests within a specific class should run? Or I'm a way off base on the design pattern here and need to use a different approach?
Even if you considered it but did not go that way, #depends is what you need. It's not meant only for passing values, but also for your exact need.
Also, even if the tests are functional so you don't pass objects or data between tests, the return value can be useful for passing the ID of the entity created in the previous test, in order for loading it in the next one.

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.

Unit testing with Symfony 2 and database

I'm trying to understand the unit tests when a database is involved. My classes heavily depends on a database to do their work. I already had a look at many many answers here on stackoverflow and on the internet in general, but I'm not really happy with what I found.
One of the common problems that I see when a database is involved (MySQL in my case) is that the tests are really really long to execute and one possible solution is to use SQLite.
I can't use it everywhere in the tests because some classes uses RAW queries instead of the Doctrine querybuilder to bypass the limitation of unknown datetime functions. SQLite has a different set of functions for date values and this means that to use it in the tests I should rewrite my queries twice, one for MySQL and one for SQLite.
I decided then to stick with MySQL, but creating and dropping the schema every time a test runs takes so much time. I know that the SchemaTool class can handle the creation of a subset of the schema: would be a good solution to create only the tables I really need in the test suite or should I always use the full schema?
Example of the part of code (pseudo-code) I'm trying to test
NotificationManagerClass
constructor(EntityManager)
loadNotifications()
deleteNotification()
updateNotification()
as you can see, I inject the entity manager in the constructor of the class. The class is a service registered in the Symfony container. In the controller I then get this service and use its methods. Inside the methods I use the querybuilder because I must have access to some other services and a repository isn't container-aware. How can I decouple more than this my class? I can't think a way to do it
You mix a lot of words together, which don't all have the meaning you gave them. A quick summary of the words:
Unit tests - Tests only one class. It doesn't test nor instantiate any other classes (it uses mocks or stubs for them). It shouldn't be using a database, it should mock doctrine instead.
Web tests - These tests test how multiple classes work together using database. These are often quite slow, so you don't want to have very many very specific tests here.
MySQL and SQLite are both just database driver. SQLite is as slow as MySQL and it really doesn't matter which one you use (well, it does matter, you have to use the same driver as you use in production)
You can't mock everything, because you decided to use raw mysql functions (bad choice)... Always avoid to use mysql queries inside classes. Use either Doctrine (there are a lot of simple ways to bypass the unknown datetime functions) or put the raw queries in the Repository and mock the repository.
In short:
Don't use anything other than the tested object in unit tests (mock/stub everything else)
Web Tests should be using production tools
Don't use mysql directly in a class
Test involving a database is not a unit test. Your repositories should be tested with integration or functional tests (or acceptance if you write such).
If you have many tests involving database, that probably means you took a wrong turn somewhere, either with:
code design - your classes are coupled to the database
deciding how to test - writing too many integration tests instead of unit tests
Might be worth looking into the test pyramid: http://martinfowler.com/bliki/TestPyramid.html
By looking into how to speed up your tests you'll only continue walking the wrong path. The solution is to write more unit tests and less integration tests. Unit tests are fast, independent and isolated, therefore harder to break. Integration tests are more fragile and slow. Look into FIRST properties of unit tests.
Btw: SQLite is a dead end. It doesn't behave like mysql as it doesn't support constraints.
Your example class could be modelled as:
class NotificationManager
{
public function __construct(MyNotificationRepository $repository, MyFabulousService $service)
{}
// ... other methods
}
This way you can inject fakes of both repository and your service and test the NotificationManager in isolation.
There's no much value in unit testing query builders as you'd be testing doctrine instead of your code. It is also hard, since the query class is declared final. You can test if queries return correct results functionally. There's gonna be lot less functional tests needed if you unit test your classes properly.
If you made the MyNotificationRepository an interface, you could even decouple from doctrine.

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.

PHPUnit - test the validity of an SQL Query

I'm in the process of testing a factory class.
One of the methods must load the data in an array for an object that another method will instantiate.
That method contains the SQL query that holds a critical condition that must be tested. ( in this case only ask for the records that are "published". Ex.: WHERE published=1 ). That distinction in the SQL Query is the only detail that makes that method differ from another one, and I want to test the query execution behaviour.
Now, I can't really mock my PDO object and ask it to return a fixed result as I would not test the execution of the query by mySQL. That would make a useless test.
That leads me to think that I'll need to set up a static database with fixed test data inside it. Am I right on this or have I missed something?
Should I separate the test requiring the "test database" from the tests that are autonomous ?
I strongly agree on the part of not mocking out the PDO. At some point i want to make sure my queries work against a real database. While this might not be a unit test anymore, technically. For me it offers so much more to know that my code that handles data storage really works against the db.
What i tend to do is creating a sort of Data Access class for each Class that needs to talk to the DB and so separating out most of the business logic from the db access code.
That way i can mock out the data access when testing the classes and after that set up a "Test Database" for each "data access class" and see if those work.
#zerkms Answer (+1) already linked http://phpunit.de/manual/current/en/database.html and the only other resource i have found to be of value when it comes to DB-Testing is the Book Real-World Solutions for Developing High-Quality PHP Frameworks and Applications that has a big chapter covering this subject.
Should I separate test requiring the "test database" from the tests that are autonomous ?
Only if your testsuite gets really really big and you have runtime issues that force you to say "hitting even a testing database just takes to long for all my tests so i run those only on a continuous integration server and not while developing.
Yes, it is the common practice.
It is also the special methods for loading fixtures: http://phpunit.de/manual/current/en/database.html
What about second question: no, you should not separate them. Your tests should test the behaviour, not the details of implementation. Join test cases into test classes by logic.

Categories