Over the last year or so, I’ve discovered the wonderful world of Unit Testing. In a slightly verbose nutshell, Unit Testing involves:

  1. Trying to get PHPUnit installed (considerably easier for me on VVV than XAMPP btw)
  2. Finally getting it to work, but not quite being sure how.
  3. Reading some tutorials that get you up to speed with useful tests like
    $this->assertEquals( 1, 1 );
  4. Trying to write tests for a real world application
  5. Realising that your real-world applications consists of code that tries to encode a string, add a month onto the current date, establish what the meaning of life, the universe and everything is, and redirect the user somewhere else, all in one function.
  6. Realising that we call functions methods now
  7. Beginning to re-write large chunks of your real-world application, but writing unit tests first, then code, because that’s what you’ve learned is the correct proceedure
  8. Having your real-world client ask you why production has ground to a halt
  9. Having your real-world client look at you blankly when you explain the wonder of unit tests
  10. Continuing to write better code, but writing unit tests at a later date, generally after something broke because your real-world client couldn’t care less about your stupid unit tests.
  11. Not being able to test a whole bunch of stuff, because how do you run
    $this->assertTrue( 'the function I just ran, redirected the user somewhere else, set a cookie, and did some other stuff');

Points 1-10 may hint at the fact that I don’t consider myself an expert in these matters.

Point 11 is where I currently reside, albeit in a slightly less convoluted way (and it proves I don’t conform to the need to write lists of 10 items).

Self-deprecation aside, learning to write unit tests has informed my coding massively. Its a dry subject to get into, but its well worth persevering with. I’m still very much a work in progress, but while I learn, I plan to share the more tricky, wacky and weird things I find (along with the tricky, weird and wacky things I find in the wonderful world of WordPress development in general. So, having cut a short intro long, lets get into some code…

Testing time() based functions:
Consider the following method that returns the current time minus one second. I have no idea why you would need a function like this, but I need an excuse to show off how I override time(), so lets pretend that its not only highly necessary, but that its also vital to you to ensure its working.

function right_now_minus_one_second() {
	return date( 'Y-m-d H:i:s', time() - 1 );
}

When it comes to testing this function with PHPUnit, you could store time() to a variable and compare it to the result of the function. Nearly every time you run the test, you’d probably pass, but that noise you can hear is the sound of every formerly-trained software developer in the world shaking their heads in disbelief at our naive optimism and flowery thinking. Luckily with the clever use of namespaces we can make Cher’s dreams come true and turn back time (or fix it in our case).

Take note of the use of namespace, and the declaration of our time function outside of the test class.

Also, take note of the comment in another_test_where_we_need_the_actual_time function with regards to needing the actual value of time(). This could save you from having to spend an hour running the same test, getting the same error message, scratching your head and repeating the whole process continually before accepting that you need to change something (or maybe this approach is just unique to me?).

Our function

namespace unit_test;

class Unit_Test {

	function right_now_minus_one_second() {
		return date( 'Y-m-d H:i:s', time() - 1 );
	}

	...
}

Our Unit Test

namespace unit_test;

// Override the time() function from within our namespace.
function time() {
	return Edge_Test::$now ?: time();
}

class Edge_Test extends \WP_UnitTestCase {
	
	// Our time variable should we need to override time().
	public static $now;

	function test_right_now_minus_one_second() {

		$unit_test = new Unit_Test();

		// Store a past value for time.
		self::$now = strtotime( '12:00:00 1979-05-12' );

		// Ensure we get it back minus one second.
		$test = $unit_test->right_now_minus_one_second();
		$this->assertTrue( '1979-05-12 11:59:59' === $test );
	}

	function another_test_where_we_need_the_actual_time() {

		// Note the backslash to escape our namespace.
		$actual_time = \time();

		...
	}
}

So there you have it. Your unit test never fails, the great developers of the world shower you with praise, and Cher stops theorising about time travel.

Advertisements

One thought on “Overriding time() when unit testing with PHPUnit

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