Asked  1 Year ago    Answers:  5   Viewed   7 times

I noticed that when I run a functional test with PhpUnit, if there is a modification in the database, it is done. However, if I'm in the middle of my test and want to recover the record that was changed, it comes back to me in its old version, which is very problematic.

For example, if I have a test in which:

  1. I collect a certain item
  2. I activate it (therefore, modification in the database of its enable property) via a URL of a controller
  3. I want to check that it is active
  4. I retrieve it from the database again
  5. I check that it is active

Well, that'll return my old item to me, and tell me it's not active.

Which forces me to create a second test to retrieve it and then check that it is active

    public function testEnableArticle()
    {
        $article = $this->getLastArticle(); //Find last article
        $admin = $this->getAdmin();
        
        $this->client->loginUser($admin);
        
        // Request to enable last article
        $this->client->request('GET', sprintf("/admin/articles/%s/enable", $article->getId()));
        
        // Now my article should be enabled :
            $updatedArticle = $this->getLastArticle();
            $this->assertSame(1, $updatedArticle->getEnable());
        // But return false because here my article seems to be the previous version before enable
    }
   

So I need a second test just after to get updated article:

    public function testLastArticleIsEnabled()
    {
        $updatedArticle = $this->getLastArticle();
        $this->assertSame(1, $updatedArticle->getEnable());
        
        // And here, it works
    }

To get my last article, I'm using my custom function :

    public function getLastArticle()
    {
        return $this->manager->getRepository(Article::class)->findLastArticle();
    }

It's very weird... Can someone help me please ?

 Answers

3

It's doctrine behaviour, it keeps your entity on memory once you've fetched it. It won't fetch it again from database, so you have one and only one instance. Try to:

$this->client->request('GET', sprintf("/admin/articles/%s/enable", $article->getId()));
$this->em->refresh(article);
Thursday, April 1, 2021
 
Andres
 
5

I donno why/how but it works

here's the code :

orm:
    auto_generate_proxy_classes: "%kernel.debug%"
    entity_managers:
        extranet:
            naming_strategy: doctrine.orm.naming_strategy.underscore
            auto_mapping: true
        crawl:
            naming_strategy: doctrine.orm.naming_strategy.underscore
            connection: crawl
            mappings:
                DbBccCrawlBundle: ~

the thing is that I tried that at the start and it failed (the class X not found in...)

If anyone has an explenation, I'll be more than happy to read it.

Thanks anyway

This was the 2nd part of the question, here's the begening : The class 'X' was not found in the chain configured namespaces ... when I try a multiple connection with doctrine

Thursday, April 1, 2021
 
Eugenie
 
3

It's my understanding that the mock should be replace the real WordPressBridge, but that isn't what's happening. My original is still being used. Am I missing something?

Basically you have to replace your service somehow in the Symfony Container.

If you doing "functional testing" then probably you should create test "dummy" service for "test" env which will overwrote original one. You can do something like that:

in src/YourBundle/Resources/config/services.yml

services:
    api.wp_bridge:
        class: %api.wp_bridge.class%
        arguments: [@service_container]

in app/config/config.yml

parameters:
    api.wp_bridge.class: "ApiBundleUtilWordPressBridge"

in app/config/config_test.yml

parameters:
    api.wp_bridge.class: "ApiBundleUtilTestWordPressBridge"

Then functional test will use "ApiBundleUtilTestWordPressBridge" - cause it is executed in "test" env.

You can try to mock container and pass it to test kernel but this can be painfull without some other mocking lib (in pure PHPUnit).

Personally I am using phpspec2 for "unit" testing where mocking is just easy :) and for some "acceptance criteria" stuff I am using behat and mink

Saturday, May 29, 2021
 
muffe
 
2

You need to put any strings starting with @ in quotes:

arguments:
    ["@security.context", "@fos_user.user_manager"]

Reserved characters, like @, should be quoted. Unquoted @s were deprecated in Symfony 2.8. Symfony 3.0 will forbid you to use such definitions and will throw an exception.

If you don't have control over the bundle that registered the problematic configuration, send a pull request with a fix to the vendor. As a quick fix you can downgrade Symfony. 2.7 will work, as well as 2.8 (the later will only emit a deprecation notice).

Saturday, May 29, 2021
 
FWH
 
FWH
5

The thing is you cannot do this in setUpBeforeClass, because many things are run in setUp method. If you look at this order of run you will see setUpBeforeClass is run before setUp method and TestCase class is doing many things in the setUp method. It looks like this:

protected function setUp()
{
    if (! $this->app) {
        $this->refreshApplication();
    }

    $this->setUpTraits();

    foreach ($this->afterApplicationCreatedCallbacks as $callback) {
        call_user_func($callback);
    }

    Facade::clearResolvedInstances();

    Model::setEventDispatcher($this->app['events']);

    $this->setUpHasRun = true;
}

So what you should do is creating own setUp and tearDown methods with your own implementation like this:

protected function setUp()
{
   parent::setUp();
   // your code goes here
}

protected function tearDown()
{
   parent::tearDown();
   // your code goes here
}
Tuesday, September 28, 2021
 
ioleo
 
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share