4

我正在尝试模拟此方法:

$transformer = $this->transformerFactory->createProductTransformer($product, function (ProductInterface $product) use ($discount) {
    $product->setDiscount($discount);
});

它接受回调参数作为第二个参数,我不知道如何模拟它。

我正在使用 Mockery,所以看起来像这样:

$this->transformerFactoryMock
    ->shouldReceive('createProductTransformer')
    ->with(???) // here!

如果我将相同的回调传递给 with() 方法,则实例不匹配。如果 Mockery 不支持,我不介意使用 PHPUnit 模拟。

4

3 回答 3

2

如果您需要准确检查是否调用了回调,那么这是不可能的,因为每个\Closure实例都是唯一的,并且在您测试过的方法中您创建了新的。

但是您可以执行以下操作:

1) 验证类型的动态参数

// Assume in test case you have these mock/stub
$discount;
$product;

$transformerFactoryMock = \Mockery::mock('TransformerFactory')
    ->shouldReceive('createProductTransformer')
    ->with($product, \Mockery::type(\Closure::class))

2)检查任何隐藏的参数(在您的测试方法中调用模拟方法之前创建)

$transformerFactoryMock = \Mockery::mock('TransformerFactory')
    ->shouldReceive('createProductTransformer')
    ->with(function(...$args) use ($product) {
        // check any args
    })

3)最后,使用传递回调到模拟方法的假结果

// then mock will be
$transformerFactoryMock = \Mockery::mock('TransformerFactory')
    ->shouldReceive('createProductTransformer')
    ->andReturnUsing(function($closure) {
        // execute closure
        $closure();

        // any logic to fake return
        return;
    })

检查嘲弄复杂参数匹配声明返回值的文档

于 2020-06-02T13:11:59.360 回答
1

如果“相同的回调”意味着相同的代码,那么它不是 PHP 的相同回调,因此 Mockery 不会接受它。

var_dump(function () {} === function () {}); // false
$func = function () {};
var_dump($func === $func); // true

要检查回调类型,您可以使用 mockery::type 方法(带有参数'closure'),更精确的检查有 mockery::on。https://github.com/padraic/mockery#argument-validation

于 2014-01-21T17:43:26.520 回答
0

很难从粘贴的代码片段中准确地判断出您要在测试文件中执行的操作,但您可以模拟闭包及其参数。这是一个快速/肮脏/未经测试的示例,可以最好地猜测您要完成的工作:

class Transformer {

    protected transformerFactory;

    public function __construct($factory) {
        $this->transformerFactory = $factor;
    }

    public function doSomething(Discount $discount, ProductInterface $product) {

        return $this->transformerFactory->createProductTransformer($product, function($product) use ($discount) {
            $product->setDiscount($discount);
        });
    }

}


class TransformerTest {

    protected function makeTransformerWithFakeFactory()
    {
        $fakeFactory = \Mockery::mock('TransformerFactory');

        $transformer = new Transformer($fakeFactory);

        return array($tranformer, $fakeFactory);
    }

    protected function fakeDiscount()
    {
        return \Mockery::mock('Discount');
    }

    protected function fakeProduct()
    {
        return \Mocker::mock('ProductInterface');
    }

            // first let's test to make sure that the factory's correct method is called with correct parameters
    function test_doSomething_WhenPassedProduct_CallsCreateProductTransformerOnFactoryWithProductAndClosure()
    {
        list($transformer, $mockFactory) = $this->makeTransformerWithFakeFactory();
        $fakeDiscount = $this->fakeDiscount();
        $fakeProduct = $this->fakeProduct();

        $mockFactory->shouldReceive('createProductTransformer')->once()->with($fakeProduct, \Mockery::type('Closure'));

        $transfomer->doSomething($fakeDiscount, $fakeProduct);
    }

            // now, let's test to make sure that the $discount within the closure is called with the right method and params
        function test_doSomething_createProductTransformerCalledWithProductAndClosure_CallsSetDiscountOnProductWithDiscount()
    {
        list($transformer, $stubFactory) = $this->makeTransfomerWithFakeFactory();
        $fakeDiscount = $this->fakeDiscount();
        $mockProduct = $this->fakeProduct();
        $stubFactory->shouldReceive('createProductTransfomer')->passthru();

        $mockProduct->shouldReceive('setDiscount')->once()->with($fakeDiscount);

        $transfomer->doSomething($fakeDiscount, $mockProduct);
    }

            // now lets make sure that doSomething returns what the call to factory's createProductTransformer method returns
    function test_doSomething_createProductTransformerCalledWithProductAndClosureReturnsValue_ReturnsSameValue()
    {
        list($transformer, $stubFactory) = $this->makeTransfomerWithFakeFactory();
        $fakeDiscount = $this->fakeDiscount();
        $fakeProduct = $this->fakeProduct();
        $stubFactory->shouldReceive('createProductTransfomer')->andReturn('transformed result');

        $result = $transfomer->doSomething($fakeDiscount, $fakeProduct);

        $this->assertEquals('transformed result', $result);
    }

}
于 2014-06-03T22:10:52.413 回答