Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
dvc opened this issue Mar 26, 2015 · 10 comments
Closed

Comments

@dvc
Copy link

dvc commented Mar 26, 2015

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?

@hmillet
Copy link

hmillet commented Mar 26, 2015

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
Copy link
Author

dvc commented Mar 26, 2015

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
Copy link

hmillet commented Jul 31, 2015

This workaround works for me, thanks a lot @dvc

@mtibben
Copy link

mtibben commented Sep 2, 2015

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
Copy link
Contributor

craue commented Feb 25, 2016

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
Copy link

mtibben commented Feb 25, 2016

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
Copy link
Contributor

craue commented Feb 25, 2016

@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
Copy link

mtibben commented Feb 25, 2016

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
Copy link
Contributor

dmaicher commented Apr 9, 2019

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
Copy link
Member

alcaeus commented Apr 12, 2019

Closing as per #638 (comment).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants