RSS
 

Posts Tagged ‘PHPUnit’

All new CakePHP Tips Summer 2014

05 Aug

For CakePHP2.x

Awesome CakePHP

Check out this all new awesome CakePHP list: awesome-cakephp
Star it, fork it, enhance it 🙂

Note the cake3 branch that will proabably soon be filled rapidly with all new shiny CakePHP3 resources and plugins.

There are also a few more generic awesome lists links in there.

CakeFest 2014 coming up

Check it out – and be part of it. You can read about last year’s event here.

This year is going to be awesome (again that word^^). And not only regarding the temperatures in Madrid 😉
A few well connected people like @philsturgeon pulled some strings and the event is listed on sites like php.net.
Let’s make this the largest fest ever.

Note: My attendance app only lists a very small subset of all people actually joining the event!

Finally a book on CakePHP2.5+

CakePHP Core Developer @josegonzalez wrote a cool book on CakePHP: Rapid Application Development with CakePHP 2.
It has some real insight in topics that are not covered by the online CakePHP documentation.

Hot tip: Use the promo code DEREUROMARK when purchasing the bundle to get 20% off your purchase!

Deployment with composer and script hooks

This is already widely used in Symfony2, for example.
Here it fires the following scripts after installing/updating to clear the cache and re-build assets etc:

"scripts" : {
	"post-install-cmd" : [
		"Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
		"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
		"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
		"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
		"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile"
	],

The list of available commands be found here: getcomposer.org/doc/articles/scripts.md

Why not leveraging this for your Cake2.x app, as well?
You could re-built AssetCompress files, clear the persistent/model cache, run custom post-update hooks and so on. (DB) Migration could also be hooked in this way.

Post links inside Forms

Most probably didn’t see this change. But it allows postLink() to be used inside forms now.
The issue was, that forms don’t work inside forms. And that post links contain those inline, breaking the form around it.

You can now easily create "Delete" links or other POST links inside your forms. It can write the forms to a View block which you can output later on then.
All you need to do is set 'inline' => false:

echo $this->Form->postLink('Delete', array('action' => 'delete', 1), array('inline' => false));

And output your buffered View block after closing the form:

echo $this->View->fetch('postLink');

This also works with multiple postLink() calls. The View block would simply contain all of the forms then.

Prevent internal field names

I try to stay away from internal framework used names for fields. Once you attach Search plugin or any other additional functionality on top of your
actions, this could get messy otherwise.
The Paginator, for instance, uses "limit", "sort", "direction", "page". In order for them to not conflict with search fields on existing fields, I avoid them and
use "order" instead of "sort" or "max" instead of "limit" for field names. In case this is not avoidable or a legacy DB schema, one can add the model prefix, though: "MyModelName.sort" and would also be able to resolve the conflict. But if you can already do so in hindsight it is probably smarter.

Array and ArrayObject

The new CakePHP3 core uses ArrayObject already quite a bit.
In 2.x you probably don’t use it too much yet. But it is wise to voice a warning regarding on some flaws of ArrayObject.
This article describes it.
Basically, empty() and ArrayObject don’t play nice. It only works with count():

if (count($options)) {
	// Yes
} else {
	// No / empty
}

The alternative would be to cast it prior to checking on it: (array)$options. Then empty() would work again.

The same issue you might face in index views and alike, where you want to display a subsitute text if no records can be listed in the pagination yet:

if (empty($users) { // BAD - better use count() here then.
    echo 'No users enlisted so far';
}

This would also always fail now in CakePHP 3 without any indication whatsoever as objects replaced the arrays and render empty() invalid as check here.

The rest of those issues in the article are also quite interesting. Check them out, as well.

A complete list of "flaws" has been put together on this page. It reads like the bible of Anti-PHP, tough 🙂
Quite entertaining even in some parts. I would just read it as an informative page, though. It is good to know those things, but it is also easy to avoid or work-around them.

MySQL and returning integers

Some probably wondered why integers and other non-stringish values is often returned as string.
This has nothing to do with CakePHP itself, but with the PDO extension of PHP underneath.

But you can easily disable that with the following flags in your database.php config:

'flags' => array(
		PDO::ATTR_STRINGIFY_FETCHES => false,
		PDO::ATTR_EMULATE_PREPARES => false
	)

UUIDs as char36 vs binary16

UUIDs (Universally Unique Identifier) can be used as an alternative to the normal AutoIncrement IDs for primary keys. Use them wisely, they are larger and slower than than the AIIDs.
But if you use them, try to prevent char36.
According to tests such as storing-billions-uuid-fields-mysql-innodb, it is 6-8 times faster to use binary(16) instead of char(36) for UUIDs.
CakePHP 2.x+ supports binary just fine.

PHPUnit and Windows

You might have seen something as descibed in this issue: Weird output in your console when running unit tests.
This is mainly because the default setting for PHPUnit in the phpunit.xml(.dist) file is usually colors="true".
You can easily overwrite it in your own file and the weird output stops:

<phpunit
	colors="false"
	...

Or you can try to use the library linked in that ticket. I didn’t try that one yet.

 
No Comments

Posted in CakePHP

 

CakePHP and PHPUnit

21 Jul

Earlier I wrote about some PHPUnit tips around Cake2. At that time the old SimpleTest testing framework had just been replaced by PHPUnit. So everything around this new framework was fairly new – especially to be.

I manually installed/downloaded the test suite files since I didnt want to install any PEAR stuff – on windows this is pretty annoying anyway.
So is there a quick way to always be up to date with PHPUnit? Yes, there is. Since it is now pretty stable I want to introduce the PHPUnit plugin, which I developed together with Hyra.

Installing PHPUnit – the easy way

It never was easier. All you need for it is the PHPUnit plugin. Just open your console in your app directory and type

cake Phpunit.Phpunit install

Select your destination (APP or ROOT vendors) and done.
This will download and extract all the necessary files, and put them in your specified Vendor folder.

Note that will have to use your path to the cake console here instead of just "cake" – e.g. /Console/cake or ../lib/Cake/Console/cake.

Make sure you got CakePlugin::loadAll() – or specifically CakePlugin::load(‘Phpunit’) in your bootstrap! Otherwise the plugin will not be available.
You can now use PHPUnit through the CLI or your favourite browser right away.

See the documentation of the plugin for details. Also note the convenience tasks (‘packages’, ‘info’) to check for updates and update the plugin shell if necessary.
It also displays the so far unused pear packages.

Autoload

If you have it installed in your ROOT vendors and get some include warnings while baking put this at the top of the VENDORS/PHPUnit/Autoload.php file:

set_include_path(get_include_path().PATH_SEPARATOR.dirname(dirname(__FILE__)));

This way the vendors folder itself is also an include path and those warnings will go away.

Further setup and usage

For this I can just refer you to the official documentation.

Appendix

In my case just now, info printed the following:

# PHPUnit 3.6.11
        OK (v3.6.11)
# File Iterator 1.3.1
        OK (v1.3.1)
# Text Template 1.1.1
        OK (v1.1.1)
# PHP CodeCoverage 1.1.3
        OK (v1.1.3)
# PHP Timer 1.0.2
        OK (v1.0.2)
# PHPUnit MockObject 1.1.1
        OK (v1.1.1)
# PHP TokenStream 1.1.3
        OK (v1.1.3)
# DbUnit 1.1.2
        OK (v1.1.2)
# PHPUnit Story 1.0.0
        OK (v1.0.0)
# PHPUnit Selenium 1.2.7
        OK (v1.2.7)
# PHPUnit TicketListener GitHub 1.0.0
        OK (v1.0.0)
---------------------------------------------------------------
Unused pear packages:
# FinderFacade (v1.0.1)
# Object_Freezer (v1.0.0)
# PHPUnit_SkeletonGenerator (v1.1.0)
# PHPUnit_TestListener_DBUS (v1.0.0)
# PHPUnit_TestListener_XHProf (v1.0.0)
# PHPUnit_TicketListener_Fogbugz (v1.0.0)
# PHPUnit_TicketListener_GoogleCode (v1.0.0)
# PHPUnit_TicketListener_Trac (v1.0.0)
# PHP_CodeBrowser (v1.0.2)
# PHP_Invoker (v1.1.0)
# bytekit (v1.1.2)
# hphpa (v1.2.2)
# phpcov (v1.0.0)
# phpcpd (v1.3.5)
# phpdcd (v0.9.3)
# phploc (v1.6.4)
# ppw (v1.0.4)
# test_helpers (v1.1.0)

Available asserts

In Cake2.x and PHPUnit 3.x you have all the basic asserts available.
These include the most important ones:

  • assertTrue and assertFalse as well as assertNull
  • assertEmpty and assertNotEmpty (for arrays)
  • assertContains and assertNotContains (for strings)
  • assertEquals and assertSame (the latter also asserts the same type) and their not counterparts
  • assertLessThanOrEqual for numeric comparison
  • assertRegExp and assertNotRegExp for regexp pattern checks

On top of that, CakePHP has a few built in additions:

  • assertWithinMargin to check that a float values is within a specific value range
  • assertTextContains and assertTextNotContains to compare texts that can contain different EOL chars
  • assertTextStartsWith and assertTextEndsWith and their not counterparts to check only for the beginning or end of a string, ignoring the EOL char type
  • assertTags as CakePHP specific helper method to assert tags

A first test case

Let’s use a concrete real-life scenario. We can use the NumberLib class of my Tools plugin for this.
If you want to assert a method "average"/test in this Lib class works as expected, we first need to set up a test case file for it in /Test/Case, suffixing it with "Test":

App::uses('NumberLib', 'Tools.Utility');
class NumberLibTest extends CakeTestCase {
}

The structure of the folders in Test should be identical to the app/plugin ones. So we create it in APP/Plugin/Tools/Test/Case/Lib/Utility/NumberLibTest.php.
Also, don’t forget to App::uses() the class you want to test (and possible dependencies that are not directly loaded by that class itself).

Then use the setUp() callback to create an object for later use:

public $Number;
public function setUp() {
	parent::setUp();
	$this->Number = new NumberLib();
	// Optional custom stuff to reset/init etc.
}

We are all set, we can start with a basic test.
As a convention, test methods always start with "test". Without that they will not be recognized.

For some classes it is useful to assert the object is the correct one (and our loading process doesn’t load a wrong one).
Here we just do it for the sake of completeness:

public function testObject() {
	$this->assertInstanceOf('NumberLib, $this->Number);
}

OK, but let’s start a real test now – the test for our "average" method:

public function testAverage() {
	// It is always a good idea to test "margins", in this case an empty array coming in
	$array = array();
	$result = $this->Number->average($array);
	$expected = 0.0;
	$this->assertSame($expected, $result);
	// Then test some common values and leave the options array alone for now
	$array = array(3, 8, 4);
	$result =  $this->Number->average($array);
	$expected = 5.0;
	$this->assertSame($expected, $result);
	// Then at some point also test with the other arguments set to different values
	$array = array(0.0, 3.7);
	$result =  $this->Number->average($array, 1); // Precision of 1 insteaf of default 0
	$expected = 1.9;
	$this->assertSame($expected, $result);
}

I think that gives you a pretty good idea how it works 🙂 See more tests (in this plugin or the CakePHP core code) for more examples.

Pitfalls and tips

Sometimes you need to debug your error throwing test case. If debug() doesn’t work for you then because the fail swallows the output. Use this then:

debug($someVar); ob_flush();

The ob_flush() forces the output of the debug content even if the assert afterwards fails.

 
3 Comments

Posted in CakePHP

 

Unit-Testing Tips for 2.0 and PHPUnit

04 Dec

Quite some time ago I wrote about Unit testing. But that was still in 1.3 and with SimpleTest.
A lot has changed since then.

Execution Order

The documentation wasn’t all that clear about it. So I tried it with the following test file:

App::uses('MyCakeTestCase', 'Tools.Lib');
class TestCaseExecutionOrderTest extends MyCakeTestCase {
	public static function setUpBeforeClass() {
		parent::setUpBeforeClass();
		self::out('setUpBeforeClass');
	}
	
	public static function tearDownAfterClass() {
		parent::tearDownAfterClass();
		self::out('tearDownAfterClass');
	}
	
	public function setUp() {
		parent::setUp();
		
		$this->out('setUp');
	}
		
	public function tearDown() {
		$this->out('tearDown'); 
		
		parent::tearDown();
	}
	public function startTest() {
		$this->out('startTest');
	}
	public function endTest() {
		$this->out('endTest'); 
	}
	
	
	public function testFoo() {
		$this->out('* foo *');
	}
	
	public function testBar() {
		$this->out('* bar *'); 
	}
	
}

Note the parent calls for setUp and tearDown as well as setUpBeforeClass and tearDownAfterClass. Those need to be set. The other 2 methods don’t require this since they are not available in the parent class.
Also bear in mind that setUpBeforeClass and tearDownAfterClass need to be static. You cannot do dynamic stuff with it.

The result was pretty obvious:

setUpBeforeClass
setUp
startTest
* foo *
endTest
tearDown
setUp
startTest
* bar *
endTest
tearDown
tearDownAfterClass

Debug Output with PHPUnit >= 3.6

On the release notes of CakePHP2.0.3 you could find the note

A big difference people will notice when writing unit tests is that all output is swallowed by PHPUnit and not presented in either the web tester page nor in the CLI tester. To overcome this annoyance use the--debug modifier if you are using the CLI interface

Well, that broke a lot of existing debug code, of course.
So I tried to come up with a solution. The Shell uses a specific output(). Why not use sth like that in test cases, too?

/**
 * outputs debug information during a web tester (browser) test case
 * since PHPUnit>=3.6 swallowes all output by default 
 * this is a convenience output handler since debug() or pr() have no effect
 * @param mixed $data
 * @param bool $pre should a pre tag be enclosed around the output
 * @return void
 * 2011-12-04 ms
 */
public function out($data, $pre = true) {
	if ($pre) {
		pr($data);
	} else {
		echo $data;
	}
	if (empty($_SERVER['HTTP_HOST'])) {
		# cli mode / shell access: use the --debug modifier if you are using the CLI interface
		return;
	}
	ob_flush();
}

As you probably noticed, I use it in the above "execution tryout".
You can make yourself a custom "MyCakeTestCase" class with then extends the core test case class and put it in there.

UPDATE January 2012

The core (>=2.0) now contains a native way to enable debugging output for your tests.
You need to append &debug=1 to the url. Not ideal, but it works*.

  • As long as your tests run through. On error the debug output will still be swallowed and you need to use the above snippet or append ob_flush() to all debug output manually.
 
 

More great news: CakePHP 2.0 stable is out!

18 Oct

After 1.5 years of development, Cake catches up with other frameworks.
It is now as modern as most of the others while remaining the most powerful of all.
Almost none if its automatic got lost during the process of rewriting.

Some of the important aspects of 2.0

  • Faster (20-40% depending on the application)
  • Modern (>=PHP5.2 and state of the art functionality)
  • More Flexible and extensible (almost every class can be switched out with own ones)
  • Exceptions as error handling
  • PHPUnit as test suite
  • Hundreds of fixes which had to stay in 1.3 due to compatibility issues
  • Lots of enhancements and new functionality like “aliasing” – details

If you start a new project dive right into 2.0. That’s the future 🙂

For all those who like to assimilate the changes as online video:
tv.cakephp.org/video/CakeFoundation/2011/10/06/ch-ch-anges_cakephp_2_0_-_by_mark_story

Radical changes

There will be radical changes. For once the file names now match the class names. This needs quite some getting used to, but once you do, you wouldn’t want it any other way.
Also, the framework paths changed to allow more customization and overwriting.

In 1.3 the normal cake setup was:

/app/
/plugins/
/vendors/
/cake/

In 2.x it’s now:

/app/
/plugins/
/vendors/
/lib/Cake/

You can overwrite (=replace) any core class just by putting the file (using the same path/package structure) in your APP/Lib/ folder:
APP/Lib/Routing/Router.php replaces the core one, for example.

Tips for upgrading to 2.x

The migration guide will help to upgrade existing applications to the new version.
This will be quite a bit of work, though. Almost all classes are renamed, many methods and object variables have been dropped.

Your biggest help will be the cake shell script "ugrade" which is available in 2.0 now. It helps you to automatically upgrade some of the code. You can either select all or single tasks like renaming components etc.
Simply type "cake upgrade" in the console to list all available methods.
It really is a huge time safer. You should backup or commit everything before you attempt to run this script, though.

The basic steps:

  • Switch out the core first (in /lib/Cake)
  • Check what is working so far
  • Use the guide to fix the issues piece by piece until everything is working again

UPDATE:
I tried to upgrade a medium sized 1.3 app to 2.0. After finding several problems I opened a ticket.
Hopefully the upgrade process will be made smoother the next couple of weeks 🙂

Also read about some more upgrade tips on my new post here.

Last Words

I am a little bit proud to see many of my tickets and proposed changes/fixes being now part of the framework.
Contributing to such a popular and large framework is sometimes easier than one might think. Sometimes it needed only hours to approve one of my tickets. OK, sometimes it needs months.
Providing a good reason and attaching proposed changes as diff or patch can really speed up things and should encourage you to involve yourself in cake core development, as well.

 
2 Comments

Posted in CakePHP