cakephptestingtransactionsphpunitcakephp-2.6

Transaction rollback while testing in CakePhp


For some reason the transaction rollback is not working in my testCase. When I execute the same piece of code from a controller, it reverts the SQL executed well. But when executing from my test case it does not rollback.

I already tried to disable cache in the test db and changed to the newest possible cakephp version that I can use in my server which is the 2.6.13. But it not worked. Can somebody help me?

Example:

TipoLog.php:

    public function insert(){            
        $data = array(
            $this->alias => array(
                'id' => 99,
                'descricao' => 'Testing 123',
            ),
        );

        $this->getDataSource()->begin();
        $result = $this->save($data);
        $this->getDataSource()->rollback(); // should undo $this->save

        return $result;
    }

When executing it on the controller, it works nice:

MyController.php

    public function teste() {
        $this->autoRender = false;

        $this->loadModel('ControleFrequencia.TipoLog');

        $id = 99;

        debug($this->TipoLog->findById($id)); //returns nothing - OK
        $this->TipoLog->insert($id);
        debug($this->TipoLog->findById($id)); //returns nothing - OK
    }

But when I execute the testCase, the rollback doesn´t work:

MyTestCaseTest.php

    public function testTest() {

        $TipoLog = ClassRegistry::init('ControleFrequencia.TipoLog');
        $id = 99;

        debug($TipoLog->findById($id));    //returns nothing - OK
        $TipoLog->insert($id);
        debug($TipoLog->findById($id));    //returns the inserted row - NOT OK
    }

SQL-LOG of the testCase

...
192 BEGIN                                   
193 SELECT COUNT(*) AS `count` FROM `my_db_test`.`tipo_log` AS `TipoLog` WHERE `TipoLog`.`id` = 99
194 SELECT COUNT(*) AS `count` FROM `my_db_test`.`tipo_log` AS `TipoLog` WHERE `TipoLog`.`id` = 99
195 SELECT COUNT(*) AS `count` FROM `my_db_test`.`tipo_log` AS `TipoLog` WHERE `TipoLog`.`descricao` = 'Testing 123' AND `TipoLog`.`id` != 99
196 SELECT COUNT(*) AS `count` FROM `my_db_test`.`tipo_log` AS `TipoLog` WHERE `TipoLog`.`id` = 99
197 SELECT COUNT(*) AS `count` FROM `my_db_test`.`tipo_log` AS `TipoLog` WHERE `TipoLog`.`id` = 99
198 INSERT INTO `my_db_test`.`tipo_log` (`id`, `descricao`) VALUES (99, 'Testing 123')
199 ROLLBACK
200 SELECT `TipoLog`.`id`, `TipoLog`.`descricao` FROM `my_db_test`.`tipo_log` AS `TipoLog` WHERE `TipoLog`.`id` = 99 LIMIT 1

database.php

public $default = array(
    'datasource' => 'Database/Mysql',
    'persistent' => false,
    'host' => 'myhost',
    'login' => 'mylogin',
    'password' => 'mypass',
    'database' => 'my_db',
    'prefix' => '',
);
public $test = array(
    'datasource' => 'Database/Mysql',
    'persistent' => false,
    'host' => 'myhost',
    'login' => 'mylogin',
    'password' => 'mypass',
    'database' => 'my_db_test',
    'prefix' => '',
);

Solution

  • That is because, by default CakePHP fixtures use MEMORY DB engine, which does not support transactions feature.

    https://dev.mysql.com/doc/refman/5.7/en/memory-storage-engine.html

    You can check this by running debug($this->query("SHOW CREATE TABLE tipo_log;")); somewhere in your test.

    To fix this, you need to set your fixture class $canUseMemory attribute to false. This will make your fixture use a DB engine, your table was created with.

    Like next:

    class TipoLogFixture extends CakeTestFixture {
    
        public $canUseMemory = false;
    
        public $import = ['model' => 'TipoLog'];
    
        public $records = [
            ...
        ];
    }