我正在为我的PHP项目编写一个单元测试,
单元测试是模拟php://input
数据
我读了这本手册,它说:
php:// input是一个只读流,允许您读取原始数据 来自请求机构。
如何模拟php://input
,或在我的PHP中编写请求正文?
这是我的源代码和单元测试,两者都是简化。
来源:
class Koru
{
static function build()
{
// This function will build an array from the php://input.
parse_str(file_get_contents('php://input'), $input);
return $input;
}
//...
单元测试:
function testBuildInput()
{
// Trying to simulate the `php://input` data here.
// NOTICE: THIS WON'T WORK.
file_put_contents('php://input', 'test1=foobar&test2=helloWorld');
$data = Koru::build();
$this->assertEquals($data, ['test1' => 'foobar',
'test2' => 'helloWorld']);
}
答案 0 :(得分:9)
请参阅vfsStream package和this SO question and answers。
基本上,您需要参数化读取数据以接受路径的服务:
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, {
type: 'pie',
data: {
labels: [
"a",
"b",
],
datasets: [{
data: [10, 20],
backgroundColor: [
"#DA1A32",
"#F0FFFF"
],
borderWidth: false,
borderColor: false
}]
},
options: {
cutoutPercentage: 0.9
}
});
然后,在测试中,提供vfsStream流路径:
public function __construct($path)
{
$data = file_get_contents($path); // you might want to use another FS read function here
}
在您的代码中,您将按常规提供\vfsStreamWrapper::register();
\vfsStream::setup('input');
$service = new Service('vfs://input')
。
答案 1 :(得分:6)
考虑到问题中的代码,最简单的解决方案是重构代码:
class Koru
{
static function build()
{
parse_str(static::getInputStream(), $input);
return $input;
}
/**
* Note: Prior to PHP 5.6, a stream opened with php://input could
* only be read once;
*
* @see http://php.net/manual/en/wrappers.php.php
*/
protected static function getInputStream()
{
return file_get_contents('php://input');
}
并使用测试双:
class KoruTestDouble extends Koru
{
protected static $inputStream;
public static function setInputStream($input = '')
{
static::$inputStream = $input;
}
protected static function getInputStream()
{
return static::$inputStream;
}
}
然后测试方法使用测试double,而不是类本身:
function testBuildInput()
{
KoruTestDouble::setInputStream('test1=foobar&test2=helloWorld');
$expected = ['test1' => 'foobar', 'test2' => 'helloWorld'];
$result = KoruTestDouble::build();
$this->assertSame($expected, $result, 'Stuff be different');
}
问题中的场景的大多数困难都是由静态类方法的使用引起的,静态类使测试变得困难。如果可能的话,可以避免使用静态类,并使用允许使用mock objects解决同类问题的实例方法。
答案 2 :(得分:2)
这种极端分解没有任何好处,导致代码非常脆弱。您的测试应该表达您的接口的期望,而不是您提供给他们的数据:PHP在以后的某个版本中是否真的无法自由返回["test2"=>"helloWorld","test1"=>"foobar"]
?如果你的代码被破坏了吗?你认为你正在测试什么 ?
我认为你过度复杂了。
$a->doit
应将$input
作为参数,而不是将Koru::build
作为其初始化的一部分。然后,您可以测试$a->doit
,而不是测试parse_str。
如果你坚持按下这个例子,那么Koru::build
需要采用'php://input'
的参数 - 这通常被称为依赖注入,你可以告诉你的函数他们需要知道的一切。然后,当你想要"测试"事情,你可以简单地传递一些其他文件(或例如data url)。
答案 3 :(得分:1)
使用Kahlan,您可以像这样直接修补file_get_contents
函数:
use My\Name\Space\Koru;
describe("::build()", function() {
it("parses data", function() {
allow('file_put_contents')->toBeCalled()->andRun(function() {
return 'test1=foobar&test2=helloWorld';
});
expect(Koru::build())->toBe([
'test1' => 'foobar',
'test2' => 'helloWorld'
]);
});
});
答案 4 :(得分:1)
使用Zend \ Diactoros \ Stream
https://zendframework.github.io/zend-diactoros/usage/
$_POST['foo'] = 'bar';
use Zend\Diactoros\ServerRequestFactory;
$psrRequest = ServerRequestFactory::fromGlobals();
var_dump($psrRequest->getParsedBody()); // foo => bar
var_dump($_POST); // foo => bar
更多信息https://laracasts.com/discuss/channels/general-discussion/psr-7?page=1