gpt4 book ai didi

php - 如何在 PHP 中为单元测试伪造资源?

转载 作者:行者123 更新时间:2023-12-01 16:48:03 25 4
gpt4 key购买 nike

我有一个方法,打开一个套接字连接,使用,然后关闭它。为了使其可测试,我将连接处理移至单独的方法中(请参阅下面的代码)。

现在我想为 barIntrefaceMethod() 编写一个单元测试,并且需要模拟方法 openConnection()。换句话说,我需要一个假的资源

是否可能/如何在 PHP 中“手动”创建 resource 类型的变量(以便伪造像“opened files, database connections, image canvas areas and the like”等句柄)?

<小时/>

FooClass

class FooClass
{
public function barIntrefaceMethod()
{
$connection = $this->openConnection();
fwrite($connection, 'some data');
$response = '';
while (!feof($connection)) {
$response .= fgets($connection, 128);
}
return $response;
$this->closeConnection($connection);
}

protected function openConnection()
{
$errno = 0;
$errstr = null;
$connection = fsockopen($this->host, $this->port, $errno, $errstr);
if (!$connection) {
// TODO Use a specific exception!
throw new Exception('Connection failed!' . ' ' . $errno . ' ' . $errstr);
}
return $connection;
}

protected function closeConnection(resource $handle)
{
return fclose($handle);
}
}

最佳答案

根据我的评论,我认为您最好稍微重构一下代码,以消除对使用实际资源句柄实际调用的 native 函数的依赖。对于 FooClass::barInterfaceMethod 的测试,您所关心的只是它返回一个响应。该类不需要关心资源是否打开、关闭、写入等。因此这就是应该模拟的内容。

下面我用一些简单且非生产的伪代码重写了您问题中的内容以进行演示:

您的真实类(class):

class FooClass
{
public function barInterfaceMethod()
{
$resource = $this->getResource();
$resource->open($this->host, $this->port);
$resource->write('some data');

$response = '';
while (($line = $resource->getLine()) !== false) {
$response .= $line;
}

$resource->close();

return $response;
}

// This could be refactored to constructor injection
// but for simplicity example we will leave at this
public function getResource()
{
return new Resource;
}
}

您对此类的测试:

class FooClassTest
{
public function testBarInterfaceMethod()
{
$resourceMock = $this->createMock(Resource::class);
$resourceMock
->method('getLine')
->will($this->onConsecutiveCalls('some data', false)); // break the loop

// Refactoring getResource to constructor injection
// would also get rid of the need to use a mock for FooClass here.
// We could then do: $fooClass = new FooClass($resourceMock);
$fooClass = $this->createMock(FooClass::class);
$fooClass
->expects($this->any())
->method('getResource');
->willReturn($resourceMock);

$this->assertNotEmpty($fooClass->barInterfaceMethod());
}
}

对于实际的 Resource 类,您不需要对那些 native 函数包装器的方法进行单元测试。示例:

class Resource
{
// We don't need to unit test this, all it does is call a PHP function
public function write($data)
{
fwrite($this->handle, $data);
}
}

最后,如果您想保持代码不变,另一种选择是设置您实际连接到的测试夹具资源以进行测试。类似的东西

fsockopen($some_test_host, $port);
fopen($some_test_data_file);
// etc.

其中 $some_test_host 包含一些可以用于测试的数据。

关于php - 如何在 PHP 中为单元测试伪造资源?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41300828/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com