Reputation: 4980
Having some issues using PHPUnit to test my controllers.
Code I was working on so far was implementing $_POST
or other request variables:
$_SERVER['REQUEST_METHOD'] = 'POST';
$_POST = array(
'test' => true
);
Most of tests worked perfectly this way until I run into methods that take uses of filter_input_array
function:
$_SERVER['REQUEST_METHOD'] = 'POST';
$_REQUEST = $_POST = $GLOBALS['_POST'] = array(
'test' => true
);
// ....
var_dump(filter_input_array(INPUT_POST));
NULL
I'm not willing to remove filter_input
functions from not mine code, but I'm unable to make them working in tests.
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.
Any help will be appreciated.
Setting $_SERVER
with CONTENT_LENGTH
and CONTENT_TYPE
does not fix the problem. My version of PHP does not allow me to write to php://stdin
in way its described in PHP 5.6.0 chagelog (or way I understand it), but file_put_contents(STDIN,..)
succeed but does not work anyway.
Because it is a phpunit test, maybe there is some kind of annotation or phpunit.xml
entry I don't know yet, that may fix this problem in php-cgi POST setting manner.
Upvotes: 13
Views: 6845
Reputation: 815
One approach to this is to use a helper method to run your filter_input_array
inside of then mock this method during tests to use something else like filter_var_array
.
For example this use case could be accomplished by doing:
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'] );
}
}
Upvotes: 1
Reputation: 6675
If the input to filter_input_array
can only be set by the initial request, and not changed at run time, then the only way to still test it is to have a your base test proxy to another test script by making an HTTP request with the right POST data and processing the response.
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";
}
Upvotes: 13
Reputation: 22532
If none of the arguments is set, this function returns NULL
, not an array of NULL values.
// No POST vars set in request
$_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
While filtering input arrays, be careful of what flags you set besides FILTER_REQUIRE_ARRAY
. For example, setting the flags like so:
<?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.
Upvotes: 1
Reputation: 8741
It seems like this is a limitation of PHP, filter_input_array()
does not allow a $_POST
array modified at runtime. See this bug for some more information. The workaround is probably to use one of the other filter functions and pass in the $_POST
array yourself.
Upvotes: 7