Wow, it sure took me a long time to find an example of how to write a unit test for my CakePHP console (shell) commands. There’s no how-to in the CakePHP documentation, and the only blog post I could find was this thing from 2009 and a correspondingly outdated version of the software.
I eventually found some code on github that Mark Story himself had written for a side project, and using that I was able to put together a bare-bones example of how to write a unit test for a CakePHP console (shell) command.
I deliberately wrote a really dumb shell to test because I just wanted to see that a test could be written. I figured, once I had the pattern I could write more sophisticated tests.
Anyway, if you’re stuck like I was, please follow along.
Step 1: create a really dumb console
Create a file called ThingyShell.php in this folder of your CakePHP application: /app/Console/Command/
These are the contents. (Later, we’ll test the method called getFour().):
<?php
class ThingyShell extends Shell {
public function main()
{
$four = $this->getFour();
$this->out($four);
}
public function getFour()
{
return "4";
}
}
Step 2: make sure your console runs
I wanted to make sure I didn’t include any dumb errors in my dumb shell, so I ran the console locally to ensure it works:
C:\[...etc...]\app>cake Thingy Welcome to CakePHP v2.7.0-dev Console --------------------------------------------------------------- App : app Path: C:\[...etc...]\app\ --------------------------------------------------------------- 4
Step 3: create a test file
Create a file called ThingyTest.php in this folder of your CakePHP application: /app/Test/Case/Console/Command/
These are the contents:
<?php
App::uses('ConsoleOutput', 'Console');
App::uses('ConsoleInput', 'Console');
App::uses('Shell', 'Console');
App::uses('ThingyShell', 'Console/Command');
class ThingyTest extends CakeTestCase
{
public function setUp()
{
parent::setUp();
$out = $this->getMock('ConsoleOutput', array(), array(), '', false);
$in = $this->getMock('ConsoleInput', array(), array(), '', false);
$this->Thingy = $this->getMock('ThingyShell',
array('in', 'err', 'createFile', '_stop', 'clear'),
array($out, $out, $in)
);
}
public function testGetFour()
{
$expected = "5";
$actual = $this->Thingy->getFour();
$this->assertEquals($expected, $actual);
}
public function tearDown()
{
parent::tearDown();
unset($this->Thingy);
}
}
You should now be able to navigate to your tests and run Console / Command / Thingy.

You should see a nice failure message like this one:

A few comments
The getMock() method comes from PHPUnit, not from CakePHP. Mr. Story explains the parameters on a blog post from 2010.
Essentially, the ThingyShell getMock is saying: replace the methods called ‘in’, ‘err’, ‘createFile’, ‘_stop’, and ‘clear’ with the variables offered on the next line. And those variables are empty mocks of ConsoleOutput and ConsoleInput.
Any methods not replaced will run on your real ThingyShell object.
Once you’ve got this proof of concept working, you should be able to expand on it to write real unit tests on your real console shells.