5

I see that there are a number of ways to load fixture data into a database. But after a functional test, what is the best/standard way to confirm what was written to the database was correct?

The phpunit package has a whole section for this, where you can load a dataset and then use things like assertTablesEqual() to compare a table's contents with the expected contents. But that doesn't seem to be usable under Symfony2, and I can't find any other standard method.

How do others solve this problem?

Nairebis
  • 283
  • 1
  • 8
  • Related: http://stackoverflow.com/questions/10784973/how-to-set-up-database-heavy-unit-tests-in-symfony2-using-phpunit – k0pernikus Nov 06 '15 at 21:17
  • I saw that question, but unfortunately it's all about creating the fixture, and not confirming the results after a functional test, unless I'm missing some aspect of the answer. – Nairebis Nov 06 '15 at 21:21
  • 2
    It's not only about creating fixtures. That's merely your starting point. For a functional test on DB side, you have to create a DB on the fly, run your tests, and then destroy the test DB. Within the functional test you can also query your DB and check for the values. As I don't think you should be testing the acutal content of the DB, but if your repository returns the correct data after certain services have written to the DB. Keep in mind that the setup and teardown process have to be run for each test case and can make the running test take a long while. – k0pernikus Nov 06 '15 at 21:32
  • 1
    I understand creating/destroying the test DB, but it's the "within the functional test you can also query your DB and check for the values" that's the core of the question. Is there a good, standard method for verifying the values of a query? For example, [phpunit has this whole mechanism with an assert of expected table contents.](https://phpunit.de/manual/current/en/database.html), which makes it very straightforward. How are people typically doing this in Symfony? It would be tedious to have separate asserts for possibly dozens (or even hundreds) of entity fields in complex business models. – Nairebis Nov 06 '15 at 21:43
  • Your last comment made the question much more clear, alas I can only say that I only asserted the specific changed content of some entities, in order to ensure the functionality of a feature. At no point, I ensured the *entire* db to be in a certain state. – k0pernikus Nov 06 '15 at 21:53
  • I would argue that you probably don't want to be writing these sorts of functional tests. I found them to be extremely fragile. Focus more on writing unit tests for your business logic. – Cerad Nov 07 '15 at 16:25
  • I've found that you can only test so much with unit tests, and functional tests are crucial for catching subtle side effects when programs get to a certain level of complexity. The typical case is two separate units tests producing valid data, but the combination of the two produces invalid data higher up in the logic chain. And ultimately the final result is what's saved into the database. Testing individual columns is incomplete, because it's not testing that other columns are unchanged. I'm not sure what you found fragile about functional tests, but they're important. – Nairebis Nov 07 '15 at 20:12

2 Answers2

1

Symfony2 use doctrine ORM by default, or you can set other database gestion (MongoDB by exemple). Check the app\config\parameters.php file to set the database connection and the app\config\config.php to check/set the type of gestion. With a ORM, you do not need to check alot of stuff as the phpunit package, because it is already integrated into the protocole and much more. Check here for more details.

If you want to load datafixtures, you can export your actual database to save it, or either create a new one only for testing and switch databases in the app\config\parameters.php by create a new one like this app\config\parameters_dev.php. In this case, the website and your local version won't use the same database. You can also edit the app\config\parameters.php and prevent to upload it with the .gitgnore file.

  • Thanks for the response! But that's not really getting to the heart of the matter, which is doing a verification test on the results of a functional test. Let's say I load my test database, run my functional method under test, and then I have new rows in 10 tables that need to have their contents confirmed to be correct. How is that normally done? phpunit has [this whole mechanism to do it](https://phpunit.de/manual/current/en/database.html). – Nairebis Nov 06 '15 at 21:18
  • Checking the database infos is bad practices in Symfony2, especially to modify them. Entites should be the only thing that you can touch, you can use [doctrine events](http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/events.html) as preupdate or postupdate to check informations, but never do queries into the database bypassing doctrine managment. – user3504263 Nov 06 '15 at 22:54
  • The subject is testing, where I need to confirm the results of a functional test. Doctrine events aren't really relevant to that. The question is writing assertions in a functional test class that validate the database results. – Nairebis Nov 06 '15 at 23:35
0

Here is an example from a test set that includes database results. If you need to interact directly with the database in your test the entity manager can be made available to the test. For more information, see this bit of documentation. Note that results are more usually presented in a web page and read by the DOM crawler.

public function setUp()
{
    self::bootKernel();
    $this->em = static::$kernel->getContainer()
            ->get('doctrine')
            ->getManager()
    ;
    $this->tool = static::$kernel->getContainer()
            ->get('truckee.toolbox')
    ;

    $classes = array(
        'Truckee\VolunteerBundle\DataFixtures\SampleData\LoadFocusSkillData',
        'Truckee\VolunteerBundle\DataFixtures\SampleData\LoadMinimumData',
        'Truckee\VolunteerBundle\DataFixtures\SampleData\LoadStaffUserGlenshire',
        'Truckee\VolunteerBundle\DataFixtures\SampleData\LoadStaffUserMelanzane',
        'Truckee\VolunteerBundle\DataFixtures\SampleData\LoadOpportunity',
        'Truckee\VolunteerBundle\DataFixtures\SampleData\LoadVolunteer',
    );
    $this->loadFixtures($classes);
    $this->client = $this->createClient();
    $this->client->followRedirects();
}

public function testOutboxUser()
{
    $crawler = $this->login('admin');
    $link = $crawler->selectLink("Send alerts to organizations")->link();
    $crawler = $this->client->click($link);
    $outboxObj = $this->em->getRepository('TruckeeVolunteerBundle:AdminOutbox')->findAll();
    $outbox = $outboxObj[0];
    $recipient = $outbox->getRecipientId();
    $type = $this->tool->getTypeFromId($recipient);

    $this->assertEquals('staff', $type);
}
geoB
  • 4,578
  • 5
  • 37
  • 70