Keeping in mind the folder and namespacing structure I outlined in my earlier post I will move to define, via unit-tests, the expected outputs the Main
class will generate in various problematic situations; I want the Main
class to send messages in place of raising exceptions and errors and will start from the case where no /controllers
sub-folder is found or no controllers are found in the /controllers
sub-folder. To test for this cases I’ve setup a sandbox folder in the /tests
folder to simulate various scenarios, the /tests/sandbox
folder has the following structure
tests/sandbox
| /aloneMain
| | AloneMain.php // defines the \TAD\Test\AloneMain class
| /badNamesControllers
| | MainWithBadlyNamedControllers.php // defines the \TAD\Test\MainWithBadlyNamedControllers class
| | /controllers
| | | Baz.php
| | | Foo.php
| /emptyControllersFolder
| | MainWithEmptyControllersFolder.php // defines the \TAD\Test\MainWithEmptyControllersFolder class
| | /controllers
And the tests, in the file tests/MainTest.php
, are
public function testCallingShowOnMainMissingControllersFolderReturnsMessage()
{
// I expect the calling to return a message about a missing controllers folder
$regex = "/.*controllers folder.*?/uUs";
$this->expectOutputRegex($regex);
// main file sitting alone in a folder
\TAD\Test\AloneMain::show('SomeController');
}
public function testCallingShowOnMainWithEmptyControllersFolderReturnsMessage()
{
// I expect the calling to return a message about an empty controllers folder
$regex = "/.*controllers folder.*empty.*?/uUs";
$this->expectOutputRegex($regex);
// main file sitting alone in a folder
\TAD\Test\MainWithEmptyControllersFolder::show('SomeController');
}
public function testCallingShowOnMainWithNotWellNamedControllersReturnsMessage()
{
// I expect the calling to return a message about controllers not sticking to the naming convention
$regex = "/.*not.*properly named controller files.*?/uUs";
$this->expectOutputRegex($regex);
// main file sitting alone in a folder
\TAD\Test\MainWithBadlyNamedControllers::show('SomeController');
}
public function _after()
{
Main::reset();
}
Please note that I use the Main::reset
method after each test.
Testing some other minor methods
I’m not going for full code-coverage here and will implement some more test for the Main
class on minor get/set methods to make them pretty safe. More light headed users will interact with the framework using mainly the show
method so throwing exceptions here makes sense, in test code I write
public function testGetControllerReturnsNullForNonIndexOrNullControllers()
{
$this->assertNull(TestMain::getController('foo'));
TestMain::maybeInit();
$this->assertNull(TestMain::getController('foo'));
}
public function testGetControllerReturnsController()
{
TestMain::maybeInit();
$this->assertNotNull(TestMain::getController('First'));
}
public function testSetControllerSetsObjectAndUnsets()
{
$object = (object)'some';
TestMain::setController('some', $object);
$r = TestMain::getController('some');
$this->assertSame($object, TestMain::getController('some'));
TestMain::setController('some');
$this->assertNull(TestMain::getController('some'));
}
public function testGetControllersReturnsNullForNonInitializedControllers()
{
$this->assertNull(TestMain::getControllers());
}
public function testSetControllersWillSetControllers()
{
$ar = array(
'foo' => (object)'foo',
'baz' => (object)'baz',
'bar' => (object)'bar'
);
TestMain::setControllers($ar);
foreach ($ar as $key => $value) {
$this->assertEquals($value, TestMain::getController($key));
}
}
public function testSetControllerThrowsForNonStringKey()
{
$this->setExpectedException('InvalidArgumentException');
TestMain::setController(1, 'some');
}
public function testSetControllerWillThrowForNonObjects()
{
$this->setExpectedException('InvalidArgumentException');
TestMain::setController('some', 'some');
}
public function testSetControllersWillThrowForNonArrayArgument()
{
$this->setExpectedException('InvalidArgumentException');
TestMain::setControllers('foo');
}
public function testSetControllersWillUnsetControllersWithNullArgument()
{
$a = array(
'some',
'baz',
'bar'
);
foreach ($a as $key) {
TestMain::setController($key, (object)$key);
}
$this->assertNotNull(TestMain::getControllers());
TestMain::setControllers();
$this->assertNull(TestMain::getControllers());
}
And after some red and green lighting will end up with the code (that can be found on GitHub)
public static function setControllers($controllers = null)
{
if (!is_null($controllers) and !is_array($controllers)) {
throw new \InvalidArgumentException('Controllers must either be an array or null');
}
if (is_null($controllers)) {
self::$controllers = null;
return;
}
foreach ($controllers as $key => $value) {
self::setController($key, $value);
}
}
public static function getControllers()
{
return self::$controllers;
}
public static function setController($key, $value = null)
{
if (!is_string($key)) {
throw new \InvalidArgumentException('Key must be a string');
}
if (!is_null($value) and !is_object($value)) {
throw new \InvalidArgumentException('Value must be an object');
}
if (self::$controllers === null) {
self::$controllers = array();
}
self::$controllers[$key] = $value;
}
public static function getController($key)
{
if (null === self::$controllers or !in_array($key, array_keys(self::$controllers))) {
return null;
}
return self::$controllers[$key];
}
I will move, then, to the Controller
class.