作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个方法,打开一个套接字连接,使用,然后关闭它。为了使其可测试,我将连接处理移至单独的方法中(请参阅下面的代码)。
现在我想为 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/
我是一名优秀的程序员,十分优秀!