在 phpunit 测试中为 filter_input_array(INPUT_POST) 设置 $_POST

Setting $_POST for filter_input_array(INPUT_POST) in phpunit test

使用 PHPUnit 测试我的控制器时遇到一些问题。

到目前为止我正在处理的代码是实现 $_POST 或其他请求变量:

$_SERVER['REQUEST_METHOD'] = 'POST';
$_POST = array(
    'test' => true
);

大多数测试都以这种方式完美运行,直到我 运行 进入使用 filter_input_array 函数的方法:

$_SERVER['REQUEST_METHOD'] = 'POST';
$_REQUEST = $_POST = $GLOBALS['_POST'] = array(
    'test' => true
);

// ....

var_dump(filter_input_array(INPUT_POST));

NULL

我不愿意从非我的代码中删除 filter_input 函数,但我无法让它们在测试中工作。

Versionings:
PHP 5.5.9-1ubuntu4.9 (cli) (built: Apr 17 2015 11:44:57)
Apache/2.4.7 (Ubuntu)
PHPUnit 4.6.6 by Sebastian Bergmann and contributors.

我们将不胜感激。

编辑 2015.05.11

$_SERVER 设置为 CONTENT_LENGTHCONTENT_TYPE 并不能解决问题。我的 PHP 版本不允许我以 PHP 5.6.0 chagelog(或我理解的方式)中描述的方式写入 php://stdin,但 file_put_contents(STDIN,..) 成功但无论如何都行不通。

因为它是一个 phpunit 测试,也许有某种我还不知道的注释或 phpunit.xml 条目,可能会以 php-cgi POST setting 方式解决这个问题。

这似乎是PHP的限制,filter_input_array()不允许在运行时修改$_POST数组。请参阅 this bug for some more information. The workaround is probably to use one of the other filter functions 并自己传入 $_POST 数组。

如果设置了none个参数,则此函数returnsNULLnot an array of NULL values.

// 请求中没有设置 POST 变量

$_POST = array();
$args = array('some_post_var' => FILTER_VALIDATE_INT);
$myinputs = filter_input_array(INPUT_POST, $args);
var_dump($myinputs);

Expected Output: array(1) { ["some_post_var"]=> NULL } 

Actual Output: NULL

在过滤输入数组时,请注意除了 FILTER_REQUIRE_ARRAY 之外还设置了哪些标志。例如,像这样设置标志:

 <?php 
    $filter = array( 
    'myInputArr' => array('filter' => FILTER_SANITIZE_STRING, 
                          'flags' => array('FILTER_FLAG_STRIP_LOW', 'FILTER_REQUIRE_ARRAY')) 
    ); 

$form_inputs = filter_input_array(INPUT_POST, $filter); 
?> 

.. will result in a blank $form_inputs['myInputArr'] regardless of what $_POST['myInputArr'] contains.

如果 filter_input_array 的输入只能由初始请求设置,并且在 运行 时没有更改,那么仍然测试它的唯一方法是拥有一个你的基础测试代理通过使用正确的 POST 数据发出 HTTP 请求并处理响应到另一个测试脚本。

main_test.php:

<?php
$data = array(
    'testname' => 'yourtestname',
    'some_post_var' => 'some_value'
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://localhost/proxy_test.php");
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);

curl_close($ch);

if ($response == 'pass') {
  // test passed
}

proxy_test.php

<?php
$test_name $_POST['testname']; // what test to run?
$response = run_test($test_name); // run test that uses filter_input_array
if ($response) {
    echo "pass"; // used by main_test.php to check if test passed
} else {
   echo "fail";
}

一种方法是使用辅助方法 运行 您的 filter_input_array 内部然后在测试期间模拟此方法以使用其他方法,例如 filter_var_array.

例如,可以通过以下方式完成此用例:

class Data_Class {

    protected function i_use_filters() {
        return $this->filter_input_array();
    }


    protected function filter_input_array() {
        return filter_input_array( INPUT_POST );
    }
}

class Test_Class extends TestCase {

    public function test_filters() : void {
        $mock = $this->getMockBuilder( Data_Class::class )
                     ->setMethods( [ 'filter_input_array' ] )
                     ->getMock();
        $mock->method( 'filter_input_array' )
             ->willReturnCallback( function () {
                 if ( ! isset( $_POST ) ) {
                     return null;
                 }
                 return \filter_var_array( $_POST );
             } );

        $_POST['test'] = true;
        $this->assertTrue( $mock->i_use_filters()['test'] );
    }
}