Unit Test using CHtml::link() and failing due to error "Trying to get property of non-object"

I have been running into a problem where I have a unit test named UiTest that tests a class named Ui. The class Ui has a static function that uses CHtml::link() to generate a hyperlink. I get error:

[color="#FF0000"]UiTest::testAllArguments()

Trying to get property of non-object[/color]

This makes sense because on CHtml.php:66 the class is looking for the value Yii::app()->charset. In this unit test we don’t create an instance of Yii::app() so the request for the charset produces the error message shown above. This must be a common issue for anyone that test unit tests without creating instances of Yii in their setUp (not that I think you would want to though). I haven’t figured out (after a lot of testing) how people get around this.

I’m using Netbeans, XDebug 2.1, and PHPUnit 3.5.13 on OS X for anyone interested.

I’d appreciate assistance from anyone that has gone through this before. Thanks.

[font=arial, verdana, tahoma, sans-serif][size=2]The most common practice is to instantiate CWebApplication in test bootstrap file. This file will be generated automatically if you use yiic webapp command to create skeleton application. Classic unit testing - where classes are tested in almost perfect isolation - can’t be done with Yii. Yii’s testing framework focuses more on database- and functional testing which I found a perfectly valid approach to a typical web application (but can be a deal-breaker for some developers/teams).[/size][/font]

Thanks for replying.

Before I get into things, can you give me an example of how you have successfully instantiated CWebApplication in the bootstrap.

Now, your comment led me in the right direction where at the end you’ll see I solved many of my issues but not all:

I started using bootstrap.php but started getting errors from CThemeManager about my theme folder not being available and I was getting stack traces in my output because of a number of custom components that rely on CHttpRequest (not gonna happen in a unit test). What I did was update the file /protected/config/test.php to reflect the following changes:

  • I commented out the reference to main.php since that contained the problem-introducing Component references

  • I took the critical elements from /config/main.php and added them to a new array




<?php

return CMap::mergeArray(

	//require(dirname(__FILE__).'/main.php'),

	//This is the newly introduced array below

	array(

		'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',

		'name'=>'App Name',

		'theme'=>'default', // the theme name I use in config/main.php

		'language'=>'en',

	),

	// This array already existed

	array(

		'components'=>array(

			'fixture'=>array(

				'class'=>'system.test.CDbFixtureManager',

			),

		),

	)

);



What I believe is that the bootstrap will use this simplified config to create a simplified Yii::app() instance that I can use in my unit testing.

All of this now work in Netbeans but it does not work via command line because it doesn’t know what Yii is. I image this has to do with the need to instantiate CWebApplication.

The command line error I get is:




bash-3.2# phpunit UiTest.php

PHP Fatal error:  Class 'Yii' not found in /Users/sites/yiiapp/protected/tests/unit/UiTest.php on line 8



Line 8 is:




Yii::import('application.helpers.ui.Ui'); // importing the class I'm testing against



Try to create a new application in a temporary folder with yiic webapp and take a look at the generated files in protected/tests. It should work out of the box.

You probably configured bootstrap file path in Netbeans so it launches phpunit with --bootstrap option and always provides the right path, which may not be the case when you start phpunit from command line. You should either use --bootstrap (or --configuration) option or launch phpunit from protected/tests (if you have a configuration xml file).

Thanks. I think the reasons it wasn’t working for me make sense (my custom Components loaded) and adding some configuration keys to /config/test.php seems to have done the trick. I essentially get a small Yii app running after bootstrap.php executes


Yii::createWebApplication($config);

You nailed it exactly. Thanks!