我试图模仿这种方法:
$transformer = $this->transformerFactory->createProductTransformer($product, function (ProductInterface $product) use ($discount) {
$product->setDiscount($discount);
});
它接受callback参数作为第二个参数,我不知道如何模拟它。
我正在使用Mockery,因此看起来像那样:
$this->transformerFactoryMock
->shouldReceive('createProductTransformer')
->with(???) // here!
如果我将相同的回调传递给with()方法,则实例不匹配。 如果Mockery不支持,我不介意使用PHPUnit模拟。
答案 0 :(得分: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
答案 1 :(得分:1)
如果您需要检查调用是否正确,则不可能,因为每个\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;
})
检查mockery complex argument matching和declaring return value的文档
答案 2 :(得分:0)
很难从您粘贴的代码段中准确地告诉您在测试文件中尝试做什么,但是您可以模拟Closures及其参数。这是一个快速/肮脏/未经测试的例子,可以最好地猜测你想要完成的事情:
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);
}
}