22

I'm on CakePHP v3.x with phpunit v5.1.3. and my unit test does not seem to be recognizing the existance of my fixtures. It appears that the tests are reading from the local (default) database connection.

Here's my TestCase class:

namespace App\Test\TestCase\Model\Table;

use Cake\Datasource\ConnectionManager;
use Cake\I18n\Time;
use Cake\ORM\TableRegistry;
use Cake\TestSuite\TestCase;

/**
 * App\Model\Table\ScreensTable Test Case
 *
 * @property \App\Model\Table\ScreensTable ScreensTable
 */
class ScreensTableTest extends TestCase
{
    /**
     * Fixtures
     *
     * @var array
     */
    public $fixtures = [
        'app.screens'
    ];

    /**
     * setUp method
     *
     * @return void
     */
    public function setUp()
    {
        parent::setUp();
        $config = TableRegistry::exists('Screens') ? [] : ['className' => 'App\Model\Table\ScreensTable'];
        $this->Screens = TableRegistry::get('Screens', $config);
    }

    public testSomethingHere(){
         $newScreen = $this->Screens->newEntity(['who' => 'cares']);
         $screen = $this->Screens->save($newScreen);
         // ^ This record will show up in my app's DB!
    }

Here's my fixture file:

<?php
namespace App\Test\Fixture;

use App\TestSuite\Fixture\TestFixture;

/**
 * ScreensFixture
 *
 */
class ScreensFixture extends TestFixture
{
    /**
     * Records
     *
     * @var array
     */
    public $records = [
        [
            'id' => 2,
            'name' => 'Bla bla',
        ],
        ...

When I debug() the returned value from $this->Screens->find('all')->order(['id'=>'ASC'])->first() I see the first REAL record in the DB. Not my fixture.

What am I missing?

UPDATE1: Here are the connections defined in my config file:

'Datasources' => [
    'default' => [
        'className' => 'Cake\Database\Connection',
        'driver' => 'Cake\Database\Driver\Postgres',
        'persistent' => false,
        'host' => 'localhost',
        'port' => '5432',
        'username' => 'postgres',
        'password' => 'postgres',
        'database' => 'transitscreen',
        'encoding' => 'utf8',
        'timezone' => 'UTC',
        'cacheMetadata' => true,
        'quoteIdentifiers' => false,
    ],
    /**
     * Used by test suites
     */
    'test' => [
        'className' => 'Cake\Database\Connection',
        'driver' => 'Cake\Database\Driver\Postgres',
        'persistent' => false,
        'host' => 'localhost',
        'port' => '5432',
        'username' => 'postgres',
        'password' => 'postgres',
        'database' => 'ts_test',
        'encoding' => 'utf8',
        'timezone' => 'UTC',
        'cacheMetadata' => true,
        'quoteIdentifiers' => false,
    ],
],

Update

The contents of App\Test\Fixture (Don't think there's anything interesting happening here... I think it's just extending the Cake fixture class)

<?php

namespace App\TestSuite\Fixture;

use Cake\I18n\Time;
use Cake\TestSuite\Fixture\TestFixture as CoreTestFixture;

/**
 * Override core TestFixture.
 */
class TestFixture extends CoreTestFixture
{

    /**
     * Initialize the fixture.
     *
     * @return void
     * @throws \Cake\ORM\Exception\MissingTableClassException When importing from a table that does not exist.
     */
    public function init()
    {
        $this->setRecordTimestamps();
        $this->encodeJsonColumns();

        parent::init();
    }

    /**
     * Set record timestamps.
     *
     * - created
     * - modified
     *
     * @return void
     */
    public function setRecordTimestamps()
    {
        foreach (['created', 'modified'] as $timestampField) {
            if (array_key_exists($timestampField, $this->fields)) {
                foreach ($this->records as &$record) {
                    $record[$timestampField] = new Time();
                }
            }
        }
    }

    /**
     * Encode JSON columns.
     *
     * Bake will output JSON fields as arrays (because of the `JsonType` object mapped to this field) but since
     * migrations execute directly against the database we need to encode these fields manually before insertion.
     *
     * @return void
     */
    public function encodeJsonColumns()
    {
        $fixtureName = namespaceSplit(get_called_class())[1];
        if ($fixtureName === 'DatasourcesFixture' && array_key_exists('widget_options', $this->fields)) {
            foreach ($this->records as &$record) {
                $record['widget_options'] = json_encode($record['widget_options']);
            }
        }
    }
}
emersonthis
  • 32,822
  • 59
  • 210
  • 375
  • @AD7six I added my database configs above. It looks right to me, as I have `default` and `test` defined and I don't get any DB connection errors when I run my tests. – emersonthis Sep 09 '16 at 20:33
  • Have you added the fixture listener to your phpunit.xml ? – code-kobold Sep 10 '16 at 08:12
  • @code-kobold oooo I'm not sure! Please submit and answer with what I should check for. – emersonthis Sep 11 '16 at 16:46
  • @emersonthis the sql log is much more useful/relevant as it will demonstrate that either the wrong db is being used or not, the key point of "alternatively" is to provide enough info _to reproduce the problem_; `App\TestSuite\Fixture\TestFixture` now that you've provided it's source doesn't allow that. – AD7six Sep 18 '16 at 09:48
  • @AD7six can you elaborate? Why isn't it allowed? – emersonthis Sep 28 '16 at 12:35
  • @AD7six you said `now that you've provided it's source doesn't allow that` and I don't understand what that means. Do you see a problem in that class that is problematic? – emersonthis Sep 29 '16 at 00:37
  • Here's a diff and what I have asked for to be crystal clear https://gist.github.com/AD7six/4b7f3e7e880b3e051bab47fd97b20b9c – AD7six Sep 29 '16 at 09:49
  • @AD7six got it. I'm actually having trouble reproducing the issue right now also. It looks like some upstream PRs might have fixed it by accident because there was some edits to our fixtures etc. when I have a minute I'll try to checkout an earlier commit and reproduce it. Thanks for your help – emersonthis Sep 29 '16 at 16:27

1 Answers1

2

Have you tried reducing the scope of the problem by:

  1. Removing the inheritance with App\Test\Fixture
  2. Defining the Fixture schema by declaring the $fields property.
  3. Enabling query logging

Both of these would be temporary measure to try and make the problem simpler to solve. You might also want to use the --debug flag when running PHPUnit. This will make CakePHP output all the SQL used to create fixtures.

Mark Story
  • 1,269
  • 6
  • 12