Skip to content

Close connections and clear managers on shutdown should be *optional* in test mode #407

Closed
@dvc

Description

@dvc

Related to: #366
Almost all our functional tests has been broken by #366 ! :(

Our project has very complex user-account-roles-subscriptions relations an hierarchy. And very complex bussiness objects inheritance and relations. It is a real pain to emulate realistic test environment... So, the decision for us:

  1. Create maximum of dictionaries, users and user data at once, before all tests.
  2. Instance one connection in setUp() and set it in custom Client and start transaction
  3. It allows to test some multipage workflows, check data directly from server-side before/after any request and rollback all modifications in tearDown(). Fast and clear.

See http://alexandre-salome.fr/blog/Symfony2-Isolation-Of-Tests for details

This recipe doesn`t work after #366.

Can you make this good functional configurable?

Activity

hmillet

hmillet commented on Mar 26, 2015

@hmillet

Got exactly the same trouble.

Using the same trick of Alexandre Salome to isolate my PHPUnit - FrameworkBundle\Client tests.

How to get a good new way to isolate our tests ?

Maybe have a way to tell the connection that if it close, it should rollback the transaction, and not commit it

dvc

dvc commented on Mar 26, 2015

@dvc
Author

May be workaround to avoid new code:

  # app/AppKernel.php

    /**
     * Обходим принудительное закрытие коннекта
     *
     * @see https://github.com/doctrine/DoctrineBundle/issues/407
     *
     * {@inheritdoc}
     *
     * @api
     */
    public function shutdown()
    {
        if (false === $this->booted) {
            return;
        }

        $this->booted = false;

        foreach ($this->getBundles() as $bundle) {
            /**
             * Вмешиваемся только в один класс и только в тестовой среде окружения
             */
            if ($bundle instanceof Doctrine\Bundle\DoctrineBundle\DoctrineBundle && ('test' === $this->getEnvironment())) {
                /**
                 * Используем замыкание для доступа к приватной переменной DoctrineBundle->autoloader
                 * @see http://habrahabr.ru/post/186718/
                 */
                $doctrineShutdown = Closure::bind(
                    function () {
                        if (null !== $this->autoloader) {
                            spl_autoload_unregister($this->autoloader);
                            $this->autoloader = null;
                        }
                    },
                    $bundle,
                    'Doctrine\Bundle\DoctrineBundle\DoctrineBundle'
                );
                $doctrineShutdown();
            } else {
                $bundle->shutdown();
            }

            $bundle->setContainer(null);
        }

        $this->container = null;
    }
hmillet

hmillet commented on Jul 31, 2015

@hmillet

This workaround works for me, thanks a lot @dvc

mtibben

mtibben commented on Sep 2, 2015

@mtibben

I have the same problem. We run each test inside a transaction, which is rolled back on teardown. This keeps the test db in a clean state without the need to rebuild it for each test.

When using symfony's test client to simulate http requests, after each request the kernel is shutdown which now means all connections are closed.

It would be nice if there was a way to avoid that.

craue

craue commented on Feb 25, 2016

@craue
Contributor

I'm stuck on DoctrineBundle 1.3 because of this issue. It breaks a lot of my tests where assertions on entities are made after a request.

mtibben

mtibben commented on Feb 25, 2016

@mtibben

I worked around the issue by decorating the connection in tests and noop
the close function

On Thu, 25 Feb 2016, 9:28 PM Christian Raue notifications@github.com
wrote:

I'm stuck on DoctrineBundle 1.3 because of this issue. It breaks a lot of
my tests where assertions on entities are made.


Reply to this email directly or view it on GitHub
#407 (comment)
.

craue

craue commented on Feb 25, 2016

@craue
Contributor

@mtibben, currently I'm calling close manually in tearDown, so noop-ing it is not an option. I tried @dvc's shutdown code and it would solve the issue, but I'd prefer a proper fix/feature instead of such a workaround.

mtibben

mtibben commented on Feb 25, 2016

@mtibben

Yeah to get around that I created a rollbackTestTransactionAndClose function - here's the code

<?php

namespace AppBundle\Framework;

use Doctrine\DBAL\Connections\MasterSlaveConnection;
use Exception;

// Decorates a connection to disable $connection->close()
//
// Every test we run is isolated within a DB transaction.
//
// However Doctrine closes all connections on kernel shutdown.
//
// This is a problem because in some tests the kernel is booted
// and shutdown multiple times (e.g. when using the WebTest client)
// which means Doctrine is closing the active transaction
// established in TestDatabaseConnectionFactory
//
// To work around the issue we stop the connection from being closed
//
// Also see https://github.com/doctrine/DoctrineBundle/issues/407
class TestDatabaseConnection extends MasterSlaveConnection
{
    private $isTestTransactionCreated = false;

    public function connect($connectionName = null)
    {
        $result = parent::connect($connectionName);

        if ($result && $this->isConnectedToMaster() && !$this->isTestTransactionCreated) {
            $this->setNestTransactionsWithSavepoints(true);
            $this->beginTransaction();
            $this->isTestTransactionCreated = true;
        }

        return $result;
    }

    public function rollbackTestTransactionAndClose()
    {
        if ($this->isTestTransactionCreated) {
            $this->rollback();
            if ($this->isTransactionActive()) {
                throw new Exception("Didn't expect transaction to be active");
            }
        }

        parent::close();
    }

    public function close()
    {
        // no-op
    }
}
dmaicher

dmaicher commented on Apr 9, 2019

@dmaicher
Contributor

The issue is quite old but I think this bundle will simplify all your transactional test logic quite a bit 😉

https://github.com/dmaicher/doctrine-test-bundle

alcaeus

alcaeus commented on Apr 12, 2019

@alcaeus
Member

Closing as per #638 (comment).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @alcaeus@dvc@craue@dmaicher@mtibben

        Issue actions

          Close connections and clear managers on shutdown should be *optional* in test mode · Issue #407 · doctrine/DoctrineBundle