Search code examples
phpsql-serversymfonydoctrinephpunit

Strange behavior of symfony doctrine during phpunit test - field becomes null in database


I am using

  • Symfony v6.4.8
  • doctrine/orm 2.19.5
  • phpunit/phpunit 9.6.19

I have build an REST API GET endpoint /api/contract/{$id} in Symfony.

It performs an API request at another system, receiving that data and combining it with local database data and creates a new record in my database.

The problem I have is at / after the persist()/flush() in the Database, that sometimes the field $contract->eup is NULL in the database.

eup is defined as nvarchar(10) in a MSSQL database.

private function saveContract(EntityManager $em, array $data): ContractData
{        
    $contract = new ContractData();
    // [... some more variables]
    $contract->setEup($data['eup']);  // example: "2024-06-29"
    
    $em->persist($contract);
    $em->flush();

    return $contract;
}

Update: simplified code of the phpunit test:

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class ContractDataControllerTest extends WebTestCase
{
    public static function contractProvider(): array
    {
        $testCases = array(
            ['18fac35b-4afe-476e-9094-1437deeb6f0a', 'stringValue1', '2024-06-29'],
        );
        return $testCases;
    }
    
    /**
     * @covers \App\Controller\API\ContractDataController::contract
     * @dataProvider contractProvider
     */
    public function testGetContractWhileLoggedIn($id, $expectValue1, $expectEup): void
    {
        $uri = $this->getUriWithSignature('/api/contract/', $id);

        $client = static::createClient();
        $client->disableReboot();
        $client->setServerParameter('HTTP_Authorization', 'Bearer ' . $_ENV['TOKEN']);
        $client->request('GET', $uri);

        $this->assertResponseStatusCodeSame(200);

        $responseData = json_decode($client->getResponse()->getContent(), true);

        $this->assertSame($expectValue1, $responseData['value1']);
        // the other values are working, there are more values to test, code is simplyfied, only eup is empty at database.
        $this->assertSame($expectEup, $responseData['valueEup']); 
    }
}

When I call my API with Postman, the record is created correctly and the eup field in the database is filled with a string.

But when I run the phpunit test php bin/phpunit --filter myTest, it calls the api, the record is created in the database, but the eup field is NULL.

  • Other fields of this record are stored correctly at the test.

  • It is also possible to write the value of this field to other fields.

  • Also tried to a shorter string, but this is also not saved.

  • I have run the test with xdebug too and can confirm (together with my colleague) that $contract->eup is set and filled with a string at $em->persist($contract); but when we look after flush at the database SELECT * FROM ... the field eup is NULL.

Do you have an idea what could be wrong?

Update2: I updated the logger config/packages/monolog.yaml

# add Doctrine-Handler
        doctrine:
            type: stream
            path: '%kernel.logs_dir%/doctrine.log'
            level: debug
            channels: ["doctrine"]

There I found out that the SQL INSERT INTO is not what i expect it to be: Executing statement: INSERT INTO contract_data (contract_number) VALUES (?) (parameters: array{"1":"XYZ123456"}, types: array{"1":2}) The eup field is missing in the SQL command!

However I don't know what to change that the field is used there.


Solution

  • My solution for the my problem with the SQL:

    delete all files in /var/cache/test/

    After that the SQL command & the test were fine!

    Attention: Deleting the complete folder was not the best idea. Now other tests failed because of missing cache files.

    Could fix it with: php bin/console cache:warmup --env=test