Testing with fixtures #2

I’ve been trying to make model tests with with fixtures, but I’m not able to load the records into the fixtures.

I’m using MySQL, I have a separate schema called “test_booking” which has empty tables corresponding to the production db. I’ve baked a fixture and model file with: “cake bake fixture Status” and “cake bake test table Status” which yielded the files below.

<?php
declare(strict_types=1);

namespace App\Test\Fixture;

use Cake\TestSuite\Fixture\TestFixture;

/**
 * StatusFixture
 */
class StatusFixture extends TestFixture
{
    /**
     * Fields
     *
     * @var array
     */
    // phpcs:disable
    public $fields = [
        'id' => ['type' => 'integer', 'length' => null, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null],
        'type' => ['type' => 'string', 'length' => 45, 'null' => false, 'default' => null, 'collate' => 'latin1_swedish_ci', 'comment' => '', 'precision' => null],
        'date' => ['type' => 'string', 'length' => 45, 'null' => false, 'default' => null, 'collate' => 'latin1_swedish_ci', 'comment' => '', 'precision' => null],
        'start_time' => ['type' => 'string', 'length' => 5, 'null' => false, 'default' => '', 'collate' => 'latin1_swedish_ci', 'comment' => '', 'precision' => null],
        'service_id' => ['type' => 'integer', 'length' => null, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null],
        'date_created' => ['type' => 'timestamp', 'length' => null, 'precision' => null, 'null' => false, 'default' => 'CURRENT_TIMESTAMP', 'comment' => ''],
        'date_modified' => ['type' => 'timestamp', 'length' => null, 'precision' => null, 'null' => false, 'default' => 'CURRENT_TIMESTAMP', 'comment' => ''],
        'manned_by' => ['type' => 'integer', 'length' => null, 'unsigned' => false, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null],
        'text' => ['type' => 'string', 'length' => 10000, 'null' => false, 'default' => '', 'collate' => 'latin1_swedish_ci', 'comment' => '', 'precision' => null],
        'active' => ['type' => 'boolean', 'length' => null, 'null' => false, 'default' => '1', 'comment' => '', 'precision' => null],
        '_constraints' => [
            'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []],
        ],
        '_options' => [
            'engine' => 'InnoDB',
            'collation' => 'latin1_swedish_ci'
        ],
    ];
    // phpcs:enable
    /**
     * Init method
     *
     * @return void
     */
    public function init(): void
    {
        $this->records = [
            [
                'id' => 1,
                'type' => 'Lorem ipsum dolor sit amet',
                'date' => 'Lorem ipsum dolor sit amet',
                'start_time' => 'Lor',
                'service_id' => 1,
                'date_created' => 1590634027,
                'date_modified' => 1590634027,
                'manned_by' => 1,
                'text' => 'Lorem ipsum dolor sit amet',
                'active' => 1,
            ],
        ];
        parent::init();
    }
}


<?php
declare(strict_types=1);

namespace App\Test\TestCase\Model\Table;

use App\Model\Table\StatusTable;
use Cake\Datasource\ConnectionManager;
use Cake\ORM\TableRegistry;
use Cake\TestSuite\TestCase;

/**
 * App\Model\Table\StatusTable Test Case
 */
class StatusTableTest extends TestCase
{
    /**
     * Test subject
     *
     * @var \App\Model\Table\StatusTable
     */
    protected $Status;

    /**
     * Fixtures
     *
     * @var array
     */
    protected $fixtures = [
        'app.Status',
    ];

    /**
     * setUp method
     *
     * @return void
     */
    public function setUp(): void
    {
        parent::setUp();
        $config = TableRegistry::getTableLocator()->exists('Status') ? [] : ['className' => StatusTable::class];
        $this->Status = TableRegistry::getTableLocator()->get('Status', $config);
    }

    /**
     * tearDown method
     *
     * @return void
     */
    public function tearDown(): void
    {
        unset($this->Status);

        parent::tearDown();
    }

    /**
     * Test getStatus method
     *
     * @return void
     */
    public function testGetStatus(): void
    {
        $status = $this->Status->getStatus(1);
        print_r($status);
        exit;
        $this->markTestIncomplete('Not implemented yet.');
    }
}

But running the tests which executes the testGetStatus() returns en empty array, instead of the record specified in the fixture. What am I doing wrong?

And in your app_local.php config file you have something like this?

'Datasources' => [
    'default' => [
        'datasource' => 'Cake\Database\Driver\Mysql',
        'host' => 'mysql.host.com',
        'username' => 'username',
        'password' => 'secret',
        'database' => 'db_prod',
    ],
    'test' => [
        'datasource' => 'Cake\Database\Driver\Mysql',
        'host' => 'mysql.host.com',
        'username' => 'username',
        'password' => 'secret',
        'database' => 'db_test',
    ],
],

By default, the fixtures will look for and write to the ‘test’ configuration and will expect that configuration name.

Yes, it looks like below.
The Status table in the stage database’s test_booking-schema exists, and is empty.
If I’ve understood it correctly, the schema and database is the same thing in MySQL.

'Datasources' => [
    'default' => [
        'datasource' => 'Cake\Database\Driver\Mysql',
        'host' => '<ip prod>',
        'username' => '<secret>',
        'password' => '<secret>',
        'database' => 'booking',
    ],
    'test' => [
        'datasource' => 'Cake\Database\Driver\Mysql',
        'host' => <ip stage>',
        'username' => '<secret>',
        'password' => '<secret>',
        'database' => 'test_booking',
    ],
],

Hmm… That’s all the obvious stuff I know about.

My own debugging strategy would be to try and locate the core code that uses the protected $fixtures property data and see what is supposed to happen. But not everyone subscribes to this grab-a-wrench style :slight_smile:

In this case, I see vendor/cake/cakephp/src/TestSuite/Fixture/FixtureManager works with the property 4 times:

The third use, load() on line 279 would be a place to look. A few debugs to see what is happening would be my approach.

One detail regarding testing and your db though; the fixture data will not only write to the db, but the tables might also get dropped and recreated from the fixture schema. I’m not certain if this a something you can configure… But I do know that when my tests are finished running the tables that were used are actually gone from the db.

In other testing news that doesn’t solve your problem;

This plugin was was demo’d at the recent Cake Meetup. It may not be a thing you want to add to the mix while you get this problem resolved but I recommend at least viewing the demo. Fixture data can get messy and a bit hard to manage as things evolve and the Factory Fixture approach can bring some relief.