如何使用Mockery模拟构造函数

Vac*_*Sir 9 php unit-testing mockery

我需要测试,代码使用某些参数创建一个新的类实例:

$bar = new ProgressBar($output, $size);
Run Code Online (Sandbox Code Playgroud)

我试图创建一个别名模拟并设置该__construct方法的期望,但它不起作用:

$progressBar = \Mockery::mock('alias:' . ProgressBar::class);
$progressBar->shouldReceive('__construct')
    ->with(\Mockery::type(OutputInterface::class), 3)
    ->once();
Run Code Online (Sandbox Code Playgroud)

这种期望从未得到满足: Mockery\Exception\InvalidCountException: Method __construct(object(Mockery\Matcher\Type), 3) from Symfony\Component\Console\Helper\ProgressBar should be called exactly 1 times but called 0 times.

你知道如何用Mockery测试这个吗?

Ale*_*sov 2

那么你不能模拟构造函数。相反,您需要稍微修改您的生产代码。正如我可以从描述中猜测你有这样的东西:

class Foo {
    public function bar(){
        $bar = new ProgressBar($output, $size);
    }
}

class ProgressBar{
    public function __construct($output, $size){
        $this->output = $output;
        $this->size = $size;
    }
}
Run Code Online (Sandbox Code Playgroud)

这不是世界上最好的代码,因为我们有耦合依赖。ProgressBar(例如,如果是值对象,则完全可以)。

首先,您应该ProgressBarFoo. 因为这样你就可以测试Foo你不需要关心如何ProgressBar工作。你知道它有效,你对此进行了测试。

但如果您仍然想测试它的实例化(出于任何原因),这里有两种方法。对于这两种方式,你都需要提取new ProggresBar

class Foo {
    public function bar(){
        $bar = $this->getBar($output, $size);
    }

    public function getBar($output, $size){
        return new ProgressBar($output, $size)
    }
}
Run Code Online (Sandbox Code Playgroud)

方式一:

class FooTest{
    public function test(){
        $foo = new Foo();
        $this->assertInstanceOf(ProgressBar::class, $foo->getBar(\Mockery::type(OutputInterface::class), 3));
    }
}
Run Code Online (Sandbox Code Playgroud)

方式二:

class FooTest{
    public function test(){
        $mock = \Mockery::mock(Foo::class)->makePartial();
        $mock->shouldReceive('getBar')
            ->with(\Mockery::type(OutputInterface::class), 3)
            ->once();
    }
}
Run Code Online (Sandbox Code Playgroud)

测试愉快!