嘲弄:测试具有不同返回值的链式方法调用(此处:Symfony ProcessBuilder)

Posted

技术标签:

【中文标题】嘲弄:测试具有不同返回值的链式方法调用(此处:Symfony ProcessBuilder)【英文标题】:Mockery: Testing chained method calls with different return values (here: Symfony ProcessBuilder) 【发布时间】:2016-07-18 16:24:46 【问题描述】:

我正在尝试使用 Symfony 的 ProcessBuilder 测试创建 2+ Process 对象(另见 API docs)的方法,并且在尝试返回不同的模拟进程对象时遇到了问题。事实上,我有点不确定Mockery 是否能做到这一点。

Mockery的andReturn()中是否可以根据对象的调用链(包括参数)来选择值?

理想情况下,我正在寻找这样的东西:

<?php
$processBuilderMock
    ->shouldReceive('setPrefix("test")->add("-f")->getProcess')
    ->andReturn($testProcess); 

完整示例: 如果文件不存在,以下代码将创建一个文件 /tmp/dummy。它为此使用了test -f /tmp/dummytouch /tmp/dummy 这两个命令(我知道这是一个愚蠢的例子)。

<?php
class Toggler

    public function toggleFile(ProcessBuilder $builder)
    
        $testProcess = $builder
            ->setPrefix('test')->setArguments(array('-f', '/tmp/dummy'))
            ->getProcess();

        $testProcess->run();

        if (!$testProcess->isSuccessful())  // (a)
            $touchProcess = $builder
                ->setPrefix('touch')->setArguments(array('/tmp/dummy'))
                ->getProcess();

            $touchProcess->run();
            return $touchProcess->isSuccessful(); // (b) 
         else 
            // ...
        
    

要测试所有情况,我需要能够模拟Process 对象以对应命令testtouch(这里:$testProcess$touchProcess)。理想情况下,测试代码如下所示:

<?php
public function testToggleFileFileDoesNotExist()

    $testProcess = \Mockery::mock('\Symfony\Component\Process\Process');
    $testProcess->shouldReceive('isSuccessful')->andReturn(false); // (a)
    $testProcess->shouldReceive('run');

    $touchProcess = \Mockery::mock('\Symfony\Component\Process\Process');
    $touchProcess->shouldReceive('isSuccessful')->andReturn(false); // (b)
    $touchProcess->shouldReceive('run');

    $builder = \Mockery::mock('\Symfony\Component\Process\ProcessBuilder');
    $builder->shouldReceive('setPrefix("test")->getProcess')->andReturn($testProcess);  // (c) Doesn't work!
    $builder->shouldReceive('setPrefix("touch")->getProcess')->andReturn($touchProcess); // (c) Doesn't work!

    $toggler = new Toggler();
    $this->assertTrue($toggler->toggleFile($builder)); // see (b)

但是,由于 Mockery 不允许在调用链中使用参数,我对如何测试这种场景有点迷茫。有什么想法吗?

【问题讨论】:

【参考方案1】:

这有点糟糕,但您可以尝试分别进入调用链的每个步骤并让它返回模拟 $builder。最后返回哪个进程取决于调用的顺序。

$builder->shouldRecieve('setPrefix')->with('test')->andReturn($builder);
$builder->shouldRecieve('setPrefix')->with('touch')->andReturn($builder);

$builder->shouldRecieve('getProcess')
    ->andReturnValues(array($testProcess, $touchProcess));

这感觉很乱,但这是迄今为止我能找到的唯一方法。 (如果您在发布此内容后提出了更好的建议,我很想知道。)

【讨论】:

以上是关于嘲弄:测试具有不同返回值的链式方法调用(此处:Symfony ProcessBuilder)的主要内容,如果未能解决你的问题,请参考以下文章

错误:在 null 上调用成员函数 create(),单元测试(嘲弄)

10-02 Java 形式参数和返回值的问题深入研究,链式编程

热门模拟具有不同类型返回值的函数?

嘲弄 os.type() 不起作用

为啥不调用具有 const 引用返回值的重载方法?

嘲弄模拟不返回指定值