php - 如何在 PHPUnit 中 stub 更复杂的方法

标签 php unit-testing testing phpunit

我正在尝试减少程序的依赖性并使其更易于测试。我这样做的一个实例是在我的一个类的 __construct() 方法中。以前,它用于获取文件名,然后 __construct() 方法将对该文件名使用 file_get_contents() 以将内容保存到属性中:

public function __construct($name){
  $this->name = $name;
  $this->contents = file_get_contents($name);
}

为了减少对文件系统的依赖,我将其替换为:

public function __construct(SplFileObject $file){
  $this->name = $file->getFilename();
  $this->contents = '';
  while(!$file->eof()){
    $this->contents .= $file->fgets();
  }
}

我相信这更容易测试,因为我可以模拟一个 SplFileObject(可以将其设置为包含我想要的任何内容)并将其传入。到目前为止我看到的示例涉及做这样的事情:

$stub = $this->getMock('SplFileObject');
$stub->expects($this->any())
     ->method('fgets')
     ->will($this->returnValue('contents of file'));

然而 SplFileObject 的 mock fgets 方法将需要更复杂 - 它需要遍历每一行内容,并在到达时停止结束。

目前我有一个可行的解决方案 - 我刚刚创建了一个名为 MockSplFileObject 的全新类,它覆盖了这些方法:

class MockSplFileObject extends SplFileObject{
    public $maxLines;
    public $filename;
    public $contents;
    public $currentLine = 1;

  public function __construct($filename, $contents){
    $this->filename = $filename;
    $this->contents = explode("\n",$contents);
    return true;
  }

  public function eof(){
    if($this->currentLine == count($this->contents)+1){
        return true;
    }
    return false;
  }

  public function fgets(){
    $line = $this->contents[$this->currentLine-1];
    $this->currentLine++;
    return $line."\n";
  }

  public function getFilename(){
    return $this->filename;
  }
}

然后我使用它而不是调用 PHPUnit 的 getMock() 函数。我的问题是:这是一种合法的做事方式吗?或者是否有更好的方法来模拟更复杂的方法?

最佳答案

$fileObject = $this->getMock('SplFileObject', [], ['php://memory']);

$fileObject
    ->expects($this->any())
    ->method('fgets')
    ->will($this->onConsecutiveCalls('line 1', 'line 2'));
$fileObject
    ->expects($this->exactly(3))
    ->method('eof')
    ->will($this->onConsecutiveCalls(false, false, true));

使用 'php://memory' 作为 SplFileObject 的参数帮助我避免了在您尝试模拟 SplFileObject 时出现的以下错误

PHP fatal error :未捕获异常“LogicException”,消息为“未调用父构造函数:对象处于无效状态”

关于php - 如何在 PHPUnit 中 stub 更复杂的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23062243/

相关文章:

javascript - 根据其他单元测试结果执行多个 Mocha 单元测试

java - 期待堆栈图框架 - Java 8

javascript - 在 php 和 html 中重写/屏蔽 url 地址

php - MySQL/PHP <select> 不显示提交的值

python - 在 Python 中测试数据库读/写和分析脚本

android - pressBack() 在 Espresso 测试中被忽略

javascript - 在 "react + react-route"堆栈上进行单元测试

php - 如何在 MySQL 查询中跳过一个单元格

javascript - 无法从通过 php 发送的 ajax 响应更新 div 文本

unit-testing - 使用 Sitecore.FakeDB 模拟 RenderingContext