【问题标题】:Simulating HTTP Request for Unit Testing模拟用于单元测试的 HTTP 请求
【发布时间】:2014-01-13 16:38:10
【问题描述】:

我正在编写一个 MVC 框架,该框架利用一个库来帮助管理输入变量(例如 get、post 等)。

现在,我正在测试 POST 和 GET 变量,方法是将它们的值分别强制放入 $_POST 和 $_GET 超全局变量中,但是在测试 PUT 和 DELETE 请求变量时遇到了障碍。

例子:

public function testGET()
{
    $_GET['test'] = 'test value';

    $get_value = Input::get('test', '[default value]');

    assertEquals('test value', $get_value);
}

有没有一种很好的方法来模拟/模拟这些变量或使用各种可用的方法(特别是 GET、POST、PUT、DELETE)来模拟 HTTP 请求?

【问题讨论】:

  • 您可以模拟 Input::get() 以返回您期望的文本,然后测试您的代码的相应行为。听起来你在正确的轨道上,你只需要做 Mock 而不是格式化全局变量。

标签: php unit-testing phpunit httprequest


【解决方案1】:

我有时觉得人们过度使用可测试性设计,最终得到的代码 80% 的复杂性似乎只是为了让测试更容易。我觉得对于那些在单元测试中变得混乱的东西来说,切换到功能测试通常会更好。

但是对于我放弃的 PHP 超级全局变量。所以我尽量避免在任何框架代码中使用 $_POST 或 $_GET,而是使用参数,或者,如果这使代码太难看,那么使用类成员或静态成员。

所以,你的 get() 函数可以这样重写:

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];
}

那么你的测试就变成了:

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

当对 Input::get() 的调用深埋在调用层次结构中时,这很快就会变得很尴尬;那么静态类成员会更好。要使用类成员,可以在 init() 函数中传递 $GET。但是如果有一个init() 函数是不合适的,它可以这样做:

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];
}

然后测试变成:

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

除此之外:我喜欢这种方法的另一个(非测试)原因是它允许客户端代码选择使用$_GET、$_POST、$_REQUEST 等。所以我将静态变量命名为@ 987654331@,并有一个init() 函数,用户需要传入$_POST 或$_GET 或任何他们想要的。

您问题的后半部分询问有关测试 PUT 和 DELETE 数据的问题。但是你没有说它是如何在真实代码中处理的。您是否有一些类似于此答案中显示的代码:https://stackoverflow.com/a/5374881/841830

如果是这样,一种方法是模拟此处显示的getContent() 函数,以返回硬编码文本,而不是从php://input 获取它。另一种方法是使用另一个函数(在您的真实类中),主要用于测试,在第一次调用将使用该变量之前进入并设置$this->content。 (那个答案中的$this->content 基本上就像我之前提到的self::$INPUT 变量。)

【讨论】:

    【解决方案2】:

    请求标头是 PHP 超级全局 $_SERVER 的一部分。您可以在 $_SERVER 中设置适当的标头。例如:

    <?php
        $_SERVER['REQUEST_METHOD'] = 'PUT';
        // Now you should be able to pull data 
    ?>
    

    参见 PHP $_SERVER 手册。 http://php.net/manual/en/reserved.variables.server.php

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-25
      • 1970-01-01
      • 2015-08-27
      • 1970-01-01
      • 2012-07-09
      • 2018-10-17
      • 2014-08-28
      相关资源
      最近更新 更多