Hands-On Unit Testing With PHPUnit

[Hands-On Unit Testing With PHPUnit][id]
[id]:http://net.tutsplus.com/tutorials/php/hands-on-unit-testing-with-phpunit/?search_index=1
## Tips

To run all test in a folder tests

    phpunit tests
   
If it is a normal project, not laravel, add the following to all test files.

    require __DIR__ . '/../vendor/autoload.php';



## Files: Sites/laravel321



Install laravel, use the following for unit test from laravel root

	cd ~/Sites/laravel321
	php artisan test
	// or create a alias
	alias t='php artisan test'
	t
	
Or add alias to .bash_profile or .zshrc

This fetch can be used as followings.

	php artisan fetch jquery
	php artisan fetch normalize
	php artisan fetch backbone
	php artisan fetch underscore
	
t will clean afer testing with phpunit's tearDown() method

Speed up by not downloading actual files. Using mock class in phpunit.

It took 6 sec, but after this it takes 0 sec.


	public function setUp()//phpunit method
	{
		$assetPath = $this->getMock('Asset');// phpunit method getMock()
		$assetPath->expects($this->any())
			->method('fetch')
			->will($this->returnValue('pseudo content'));// this will modk Asset class
			// and not download the file
		// $this->fetch = new Fetch_Task;	// original
		$this->fetch = new Fetch_Task($assetPath);// for mock	

	}
	
If you comment 

		public function tearDown()//phpUnit method
	{
		// File::cleandir(static::$cssDir);			
		// File::cleandir(static::$jsDir);
	}	
	
And run a test, by t. It will put a psedo content.
If you run php artisan fetch jquery, it will fetch jquery.

Final code 

	//application/tasks/fetch.php
	
	<?php

	class Asset {
	public function fetch($assetPath)
	{
		return file_get_contents($assetPath);
	}
	}

	class Fetch_Task {

	public static $paths = array(
		'jquery' => 'http://code.jquery.com/jquery.js',
		'backbone' => 'http://backbonejs.org/backbone.js',
		'underscore' => 'http://underscorejs.org/underscore.js',
		'normalize' => 'https://raw.github.com/necolas/normalize.css/master/normalize.css'
	);
	public static $cssDir = 'public/css/vendors/';
	public static $jsDir = 'public/js/vendors/';

	public function __construct(Asset $file = null)// need to be class of Asset
	{
		// this is simplified under this
		// if( ! is_null($file)){
		// 	$this->file = $file;
		// }
		// else
		// {
		// 	$this->file = new Asset;
		// }

		$this->file = is_null($file) ? ( new Asset ) : $file;
	}

	public function run($query = null)
	{
		if( !$query ){
			throw new InvalidArgumentException('Please pass an asset to download.');
		}
		
		$this->asset = strtolower($query[0]);

		// if recognized, 
		if( $this->recognizesAsset($this->asset) )
		{
			//then fetch it an creat the file
			// $content = $this->fetch(static::$paths[$this->asset]);
			$content = $this->file->fetch(static::$paths[$this->asset]);
			$this->createFile($this->asset, $content);
			echo 'Your asset has been generated.' . PHP_EOL;
		}
		else
		{
			// echo not found to the user
			echo "The {$query[0]} key was not recognized."  . PHP_EOL;
		}

	}


	public function recognizesAsset($asset)
	{
		return array_key_exists($asset, static::$paths);
	}

	/*
	// this one is factored out at the top
 	public function fetch($assetPath)
	{
		return file_get_contents($assetPath);
	}
	*/
	public function createFile($asset, $content)
	{
	// this will be improved under this
	// $fileExtension = pathinfo(static::$paths[$asset], PATHINFO_EXTENSION);

	// 	if( $fileExtension === 'js')
	// 	{
	// 		$path = static::$jsDir . "{$asset}.{$fileExtension}";
	// 	} elseif ($fileExtension === 'css')
	// 	{
	// 		$path = static::$cssDir . "{$asset}.{$fileExtension}";
	// 	}

		$file = pathinfo(static::$paths[$asset]);
		
		switch ($file['extension']) 
		{
			case 'js':
				$path = static::$jsDir . $file['basename'];
				break;
			
			case 'css':
			default:
				$path = static::$cssDir . $file['basename'];
		}

		File::mkdir(dirname($path));

		File::put($path, $content);
	}

    }
	
	
	
application/test/fetch.test.php

	<?php

	require path('app') . 'tasks/fetch.php';

	class Fetch_test extends PHPUnit_Framework_TestCase 
	{

	public static $cssDir = 'public/css/vendors/';
	public static $jsDir = 'public/js/vendors/';

	public function setUp()//phpunit method
	{
		$assetPath = $this->getMock('Asset');// phpunit method getMock()
		$assetPath->expects($this->any())
			->method('fetch')
			->will($this->returnValue('pseudo content'));// this will modk Asset class
			// and not download the file
		// $this->fetch = new Fetch_Task;	// original
		$this->fetch = new Fetch_Task($assetPath);// for mock	

	}

	public function tearDown()//phpUnit method
	{
		File::cleandir(static::$cssDir);			
		File::cleandir(static::$jsDir);
	}


	public function testStoresListOfAssets()
	{
		$this->assertClassHasStaticAttribute('paths', 'Fetch_Task');
		$this->assertArrayHasKey('jquery', Fetch_Task::$paths);
	}

	/** 
	 * @expectedException InvalidArgumentException
	 */
	public function testThrowsExceptionIfNoAssetIsProvided()
	{
		$this->fetch->run();
	}

	public function testDownloadsAssetIfFound()
	{
		$this->fetch->run(array('jquery'));
		$this->assertFileExists(static::$jsDir . 'jquery.js');
	}

	public function testSavesAssetsToProperDirectory()
	{
		$this->fetch->run(array('jquery'));
		$this->assertFileExists(static::$jsDir . 'jquery.js');

		$this->fetch->run(array('normalize'));
		$this->assertFileExists(static::$cssDir . 'normalize.css');
	}

	public function testNotifiesUserUponCompletion()
	{
		$this->fetch->run(array('jquery'));
		$this->expectOutputString('Your asset has been generated.'. PHP_EOL);		
	}

	public function testNotifiesUserIfAssetIsNotRecongized()
	{
		$this->fetch->run(array('blabla'));
		$this->expectOutputString('The blabla key was not recognized.'. PHP_EOL);				
	}
	}