如何使用 phpspec dataprovider 正确测试子类
How to properly test subclasses with phpspec dataprovider
我是 Phpspec 测试的新手,我不知道在将对象转换为不同的响应结构时测试多个场景的正确方法是什么。
我需要检查价格是否计算正确。这里我有 Transformer 规范测试:
/**
* @dataProvider pricesProvider
*/
public function it_should_check_whether_the_prices_are_correct(
$priceWithoutVat,
$priceWithVat,
$vat,
Request $request,
Repository $repository
) {
$productIds = array(100001);
$result = array(
new Product(
'100001',
'MONSTER',
new Price(
$priceWithoutVat,
20,
'GBP',
null,
null
)
)
);
$expected = array(
array(
"productId" => "100001",
"brand" => "MONSTER",
"price" => array(
"amount" => $priceWithVat,
"vatAmount" => $vat,
"currencyCode" => "GBP",
"discountAmount" => (int)0
)
)
);
$repository->getResult(array(
Repository::FILTER_IDS => $productIds
))->willReturn($result);
$request->get('productIds')->willReturn(productIds);
/** @var SubjectSpec $transformedData */
$transformedData = $this->transform($request);
$transformedData->shouldEqual($expected);
}
public function pricesProvider()
{
return array(
array('123.456789', 14814, 2469),
array('60.00', 7200, 1200),
);
}
在我的 Transformer class 中,我有一个函数可以将数据格式化为正确的格式:
public function transform(Request $request)
{
$productIds = $request->get('productIds');
$productsResult = $this->repository->getResult(array(
Repository::FILTER_IDS => $productIds
));
$products = array();
foreach ($productsResult as $product) {
$products[] = $this->formatData($product);
}
return $products;
}
/**
* @param Product $product
* @return array
*/
private function formatData(Product $product)
{
return array(
'productId' => $product->getId(),
'brand' => $product->getBrandName(),
'price' => array(
'amount' => (int)bcmul($product->getPrice()->getAmountWithTax(), '100'),
'vatAmount' => (int)bcmul($product->getPrice()->getTaxAmount(), '100'),
'currencyCode' => $product->getPrice()->getCurrencyCode(),
'discountAmount' => (int)bcmul($product->getPrice()->getDiscountAmount(), '100')
)
);
}
问题是,我收到此错误消息:
316 - it should check whether the prices are correct
warning: bcmul() expects parameter 1 to be string, object given in
/src/AppBundle/Database/Entity/Product/Price/Price.php line 49
如果我对这些值进行硬编码,那么测试是绿色的。但是我想测试各种价格和结果,所以我决定使用 dataProvider
方法。
但是当 dataProvider
传递 $amountWithoutTax
值时,它不是字符串而是 PhpSpec\Wrapper\Collaborator
class 并且因此 bcmul
失败。
如果我将 $amountWithoutTax
值更改为 $priceWithoutVat->getWrappedObject()
,则 Double\stdClass\P97
class 将通过,因此 bcmul
将失败。
如何进行这项工作?是陈词滥调还是我完全误解了这个概念?
我使用 https://github.com/coduo/phpspec-data-provider-extension 并且在 composer.json 中有以下内容:
"require-dev": {
"phpspec/phpspec": "2.5.8",
"coduo/phpspec-data-provider-extension": "^1.0"
}
如果 getAmountWithTax()
在你的 formatData
方法中 returns 是 PhpSpec\Wrapper\Collaborator
的一个实例,这意味着它 returns 是一个 Prophecy 模拟构建器而不是实际的模拟,即您通过调用 reveal()
方法获得的模拟。我不知道你的数据提供者是什么样子,但你似乎在嘲笑你的 Price
值对象而不是创建其真实实例,并且 $product->getPrice()
在你的生产代码中 returns对象类型错误。
解决方案是创建 Price
值对象的真实实例,稍后由 $product->getPrice()
在数据提供程序中使用 new
返回,或者通过调用 reveal()
在那个实例上,就像这样(假设 $price
是一个来自类型提示参数的模拟对象):
$product->getPrice()->willReturn($price->reveal());
我是 Phpspec 测试的新手,我不知道在将对象转换为不同的响应结构时测试多个场景的正确方法是什么。
我需要检查价格是否计算正确。这里我有 Transformer 规范测试:
/**
* @dataProvider pricesProvider
*/
public function it_should_check_whether_the_prices_are_correct(
$priceWithoutVat,
$priceWithVat,
$vat,
Request $request,
Repository $repository
) {
$productIds = array(100001);
$result = array(
new Product(
'100001',
'MONSTER',
new Price(
$priceWithoutVat,
20,
'GBP',
null,
null
)
)
);
$expected = array(
array(
"productId" => "100001",
"brand" => "MONSTER",
"price" => array(
"amount" => $priceWithVat,
"vatAmount" => $vat,
"currencyCode" => "GBP",
"discountAmount" => (int)0
)
)
);
$repository->getResult(array(
Repository::FILTER_IDS => $productIds
))->willReturn($result);
$request->get('productIds')->willReturn(productIds);
/** @var SubjectSpec $transformedData */
$transformedData = $this->transform($request);
$transformedData->shouldEqual($expected);
}
public function pricesProvider()
{
return array(
array('123.456789', 14814, 2469),
array('60.00', 7200, 1200),
);
}
在我的 Transformer class 中,我有一个函数可以将数据格式化为正确的格式:
public function transform(Request $request)
{
$productIds = $request->get('productIds');
$productsResult = $this->repository->getResult(array(
Repository::FILTER_IDS => $productIds
));
$products = array();
foreach ($productsResult as $product) {
$products[] = $this->formatData($product);
}
return $products;
}
/**
* @param Product $product
* @return array
*/
private function formatData(Product $product)
{
return array(
'productId' => $product->getId(),
'brand' => $product->getBrandName(),
'price' => array(
'amount' => (int)bcmul($product->getPrice()->getAmountWithTax(), '100'),
'vatAmount' => (int)bcmul($product->getPrice()->getTaxAmount(), '100'),
'currencyCode' => $product->getPrice()->getCurrencyCode(),
'discountAmount' => (int)bcmul($product->getPrice()->getDiscountAmount(), '100')
)
);
}
问题是,我收到此错误消息:
316 - it should check whether the prices are correct
warning: bcmul() expects parameter 1 to be string, object given in
/src/AppBundle/Database/Entity/Product/Price/Price.php line 49
如果我对这些值进行硬编码,那么测试是绿色的。但是我想测试各种价格和结果,所以我决定使用 dataProvider
方法。
但是当 dataProvider
传递 $amountWithoutTax
值时,它不是字符串而是 PhpSpec\Wrapper\Collaborator
class 并且因此 bcmul
失败。
如果我将 $amountWithoutTax
值更改为 $priceWithoutVat->getWrappedObject()
,则 Double\stdClass\P97
class 将通过,因此 bcmul
将失败。
如何进行这项工作?是陈词滥调还是我完全误解了这个概念?
我使用 https://github.com/coduo/phpspec-data-provider-extension 并且在 composer.json 中有以下内容:
"require-dev": {
"phpspec/phpspec": "2.5.8",
"coduo/phpspec-data-provider-extension": "^1.0"
}
如果 getAmountWithTax()
在你的 formatData
方法中 returns 是 PhpSpec\Wrapper\Collaborator
的一个实例,这意味着它 returns 是一个 Prophecy 模拟构建器而不是实际的模拟,即您通过调用 reveal()
方法获得的模拟。我不知道你的数据提供者是什么样子,但你似乎在嘲笑你的 Price
值对象而不是创建其真实实例,并且 $product->getPrice()
在你的生产代码中 returns对象类型错误。
解决方案是创建 Price
值对象的真实实例,稍后由 $product->getPrice()
在数据提供程序中使用 new
返回,或者通过调用 reveal()
在那个实例上,就像这样(假设 $price
是一个来自类型提示参数的模拟对象):
$product->getPrice()->willReturn($price->reveal());