Simulating HTTP Request for Unit Testing

httprequest, php, phpunit, unit-testing

Solution

I sometimes feels people over-use Design For Testability, ending up with code where 80% of the complexity seems to be just to make it easier for testing. I feel it is often better to switch to functional testing for stuff that is getting messy to unit test.

But for the PHP super-globals I give in. So I try to avoid using $_POST or $_GET in any framework code, and instead use a parameter or, if that makes the code too ugly, then a class member or static member.

So, your get() function could be rewritten like this:

public static function get($name,$default,$GET=null)
{
  if($GET===null)$GET=$_GET;  //For non-test code
  if(!array_key_exists($name,$GET))return $default;
  return $GET[$name];
}

Then your test becomes:

public function testGET()
{
    $GET=array('test' => 'test value');
    $get_value = Input::get('test', '[default value]', $GET);
    $this->assertEquals('test value', $get_value);
}

This quickly gets awkward when the call to Input::get() is buried deep in a call hierarchy; then a static class member is better. To use a class member, $GET can be passed in an `init()` function. But if having an `init()` function is inappropriate, it can be done like this:

public static $GET=null;

public static function get($name,$default)
{
  if(self::$GET===null)self::$GET=$_GET;  //Init on first call
  if(!array_key_exists($name,self::$GET))return $default;
  return $GET[$name];
}

And then the test becomes:

public function testGET()
{
    Input::$GET=array('test' => 'test value');
    $get_value = Input::get('test', '[default value]');
    $this->assertEquals('test value', $get_value);
}

Aside: another (non-testing) reason I like this approach is that it allows a client-code to choose to use `$_GET`,`$_POST`, `$_REQUEST`, etc. So I would name the static variable `self::$INPUT`, and have an `init()` function where the user is expected to pass in `$_POST` or `$_GET` or whatever they want.

The second half of your question asks about testing PUT and DELETE data. However you didn't say how it is being processed in the real code. Do you have some code similar to that shown in this answer: https://stackoverflow.com/a/5374881/841830

If so, one approach is to mock the `getContent()` function, shown there, to return hard-coded text, instead of getting it from `php://input`. Another approach is to have another function (in your real class), principally for testing, that goes in and sets `$this->content` before the first call that will use that variable. (`$this->content` in that answer is basically like the `self::$INPUT` variable I mentioned earlier.)

Problem

I'm writing an MVC framework that utilizes a library which will help manage input variables (e.g. get, post, etc.). Right now, I'm testing the POST and GET variables by forcing their values into the $_POST and $_GET superglobals, respectively, but I've reached a roadblock when testing for PUT and DELETE request variables. Example: ``` public function testGET() { $_GET['test'] = 'test value'; $get_value = Input::get('test', '[default value]'); assertEquals('test value', $get_value); } ``` Is there a good way to mock/simulate these variables or to simulate an HTTP request using the various methods available (specifically, GET, POST, PUT, DELETE)?

Original source