In an attempt to shape myself into a poster boy for “Best Practice WordPress Development”, I’ve faithfully installed, Vagrant, I write unit tests and I run Codesniffer on all the new code I write (and am painstakingly refactoring old code at the same time). On a recent job, a quick run of Codesniffer produced (among other issues):

Detected access of super global var $_POST, probably needs manual inspection.

Now I esc_attr with the best of them, and the method in question was just testing whether a variable was set before proceeding, but I’m nothing if not a stickler for best practice (as well as hating anything but a clean bill of health from Codesniffer) so I refactored my code as follows:

if ( ! isset( $_POST['refresh_rates'] ) ) {
	return false;
}

Became

$refresh = (bool) filter_input( INPUT_POST, 'refresh_rates' );

if ( ! $refresh ) {
	return false;
}

I ran Codesniffer once more, and then sat back with a satisfied grin as it skipped along merrily returning no issue. That grin was to prove to be short-lived. When it came to writing unit tests (yes, I know I should write tests before code, I also shouldn’t have opened that second bottle of wine last night, but that’s just how I roll), I could not set the $_POST variable. Better developers than me would know that you can’t modify $_POST variables during runtime. I got there in the end. So, what to do? Upset the Gods of PHPUnit or wake up screaming in the night every time I remember that Codesniffer error winking at me.

Fortunately a return to the murky world of PHPUnit MockBuilders provided all I needed to get back to sleeping comfortably through the night. Simply separate out the filter_input call into a separate method, and override it with a Stub in my unit tests. So, that’s what I did:

function refresh_rates_check() {

	$refresh = (bool) $this->my_filter_input( INPUT_POST, 'refresh_rates' );

	if ( ! $refresh ) {
		return false;
	}

	return true;
}

function my_filter_input( $type, $name ) {
	return filter_input( $type, $name );
}

Next up, write a unit test with a mock:

function test_refresh_rates_check() {

	$currency = $this->getMockBuilder( 'Currency' )
		->setMethods( [ 'my_filter_input' ] )
		->getMock();

	$currency->expects( $this->once() )
		->method( 'my_filter_input' );

	$this->assertTrue( $currency->refresh_rates_check() );
}

The observant amongst you can probably see where this is going (no one likes a smart arse though, so pipe down). I ran the test. It failed. Why? because stubs return null values. ARGH. I did what any self-respecting coder would do in the circumstances, I ran the test five more times, stomped off in a huff, made some coffee, wrote some other code that made me feel clever again, procrastinated, tried not to look this bit of code directly in the eye, then googled for help, which led me to Juan Termino’s excellent series on PHPUnit, and specifically, his post on Mock Objects, Stub Methods and Dependency Injection.

The final piece in the puzzle, was to add an extra line to the expects() method to override the null return value.

function test_refresh_rates_check() {

	$currency = $this->getMockBuilder( 'Currency' )
		->setMethods( [ 'my_filter_input' ] )
		->getMock();

	$currency->expects( $this->once() )
		->method( 'my_filter_input' )
		->will( $this->returnValue( '1' ) );

	$this->assertTrue( $currency->refresh_rates_check() );
}

Codesniffer likes me, PHPUnit returns a beautiful green box full of confirmed tests, I’m off to bed.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s