TDD, Fixtures with 1.1.5

hello everybody,

Merry Christmaaaaas …

So I have the following setup:

prefix: tbl_

table name: tbl_jobs

my protected/tests/fixtures/tbl_jobs.php fixture:




<?php

	return array(

		'job1'	=> array(

			'id'			=> 1,

			'company'		=> 'Facebook',

		),

		'job2'	=> array(

			'id'			=> 2,

			'company'		=> 'Google',

		),


	);



my protected/tests/unit/JobTest.php test case:




<?php

	class JobTest extends CTestCase

	{

		public $fixtures = array( 'jobs' => 'Job' );


		public function testCount()

		{

                        // i'm expecting 2 here -> see fixture file

			$this->assertEquals( 2,sizeof( $this->jobs  ) );	

		}

	}



and my unit-test output looks like this:




1) JobTest::testCount

Undefined property: JobTest::$jobs


/var/www/p/Project-J/protected/tests/unit/JobTest.php:10



it seems like it’s not loading my fixtures (undefined property)

What am I missing?

I have more fields in the table, but I think that should be ok ///

thx,

–iM

[size=“4”]I FOUND IT [/size]:)

so I originally created my model with the Gii tool, which didn’t add the fixtures and tests for me :confused:

after a little google-ing I re-run my model creation with the yiic tool and voi’la, everything works :D gotta love it!

the only difference that I can see was, that I extended my JobTest from CTestCase and not from CDbTestCase. Of course, now it makes sense …

so back on track …

–iM

I was having similar problems, however my solution was a bit different.

My fixtures reference looked like:




public $fixtures = array(

		'users' => 'User'

	);



But I was getting the error:




Exception: Unknown property 'users' for class 'UserTest'.



My fixture file was set to ‘User.php’, which was the problem. You have to name the file the same as the DB table with the included prefix if you’re using one.

The solution was to rename the file from ‘User.php’ to ‘tp_user.php’ where ‘tp_’ is my table prefix for the Test DB connection.

Thanks to @Nickerson for this really helps, save me a lot of time. :)

In my case, I don’t use table prefix. The tip is that one has to make fixture file name, fixture table name and the table name in database exactly the same; for example,




	// in protected/test/unit/foobarTest.php

	public $fixtures = array(

		"user" => ":user", 

	);

	



The following must reside in the fixture file named as "user.php" ("User.php" does not work).




	// in protected/test/fixtures/user.php

	return array(

	"user1" => array(

		"username" => "agent.smith@example.com", 

		"fullname" => "Agent Smith", 

	),	

	



I want to share my experiences regarding fixtures and table prefixes as I think it might be helpful for others.

For the Post model I have a table named ‘tbl_post’ and the prefix configured as ‘tbl_’. To make it work with fixtures I defined the following fixture in my test file:




protected $fixtures = array(

    '{{post}}' => 'Post',

);



As mentioned in previous posts, the fixture file needs to be named to the full table name: ‘tbl_post.php’. The file looks like this:




return array(

    'sample1' => array(

        'title' => 'post1',

        'text' => 'post1',

    ),

    'sample2' => array(

        'title' => 'post2',

        'text' => 'post2',

    ),

);



This all worked well but then I wanted to refer to the fixture data in the test cases. Normally you would be able to use the following code to refer to the fixture AR instance with alias ‘sample1’:




$this->post('sample1');



However, this doesn’t work when using a prefix and ‘{{post}}’ as the fixure name. In order to resolve this I wrote a class DbTestCase that extends CDbTestCase and overrides the PHP magic methods __get and __call. This is the result:




/**

 * Class extends from CDbTestCase to include support for fixture data getters 

 * with prefixed table names.

 */

class DbTestCase extends CDbTestCase {


    /**

     * Sets up before each test method runs.

     */

    protected function setUp() {

        parent::setUp();

    }


    /**

     * PHP magic method.

     * This method is overridden so that named fixture data can be accessed like 

     * a normal property even when a table prefix is used.

     * @param string $name the property name

     * @throws Exception if unknown property is used

     * @return mixed the property value

     */

    public function __get($name) {


        if (is_array($this->fixtures) && ($rows = $this->getFixtureManager()->getRows($name)) !== false) {

            return $rows;

        } else if (Yii::app()->db->tablePrefix !== null) {

            $name = '{{' . $name . '}}';

            if (is_array($this->fixtures) && ($rows = $this->getFixtureManager()->getRows($name)) !== false) {

                return $rows;

            }

        } else {

            throw new Exception("Unknown property '$name' for class '" . get_class($this) . "'.");

        }

    }


    /**

     * PHP magic method.

     * This method is overridden so that named fixture ActiveRecord instances 

     * can be accessed in terms of a method call even when a table prefix is used.

     * @param string $name method name

     * @param string $params method parameters

     * @throws Exception if unknown method is used

     * @return mixed the property value

     */

    public function __call($name, $params) {

        if (is_array($this->fixtures) && isset($params[0]) && ($record = $this->getFixtureManager()->getRecord($name, $params[0])) !== false) {

            return $record;

        } else if (Yii::app()->db->tablePrefix !== null) {

            $name = '{{' . $name . '}}';

            if (is_array($this->fixtures) && isset($params[0]) && ($record = $this->getFixtureManager()->getRecord($name, $params[0])) !== false) {

                return $record;

            }

        } else {

            throw new Exception("Unknown method '$name' for class '" . get_class($this) . "'.");

        }

    }


}



Extending my test case classes from this new class DbTestCase, I was able to refer to fixture data:





class PostTest extends DbTestCase {


    protected $fixtures = array(

        '{{post}}' => 'Post',

    );


    function testDelete() {

        $post = $this->post('sample1');

        $post->delete();

        $this->assertNull(Post::model()->findByPk($post->id));

    }


}




I hope this can be helpful for anyone that is using prefixes and fixtures. The only thing I’m still looking at is making the fixture file name independent from the prefix. Maybe someone has a good suggestion?