【问题标题】:How to properly test subclasses with phpspec dataprovider如何使用 phpspec dataprovider 正确测试子类
【发布时间】:2019-03-22 14:45:58
【问题描述】:

我对 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 类中,我有一个函数可以将数据格式化为正确的格式:

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 类,因此bcmul 失败。

如果我将$amountWithoutTax 值更改为$priceWithoutVat->getWrappedObject(),则Double\stdClass\P97 类将通过,因此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"
}

【问题讨论】:

  • 当您在测试本身中 var_dump $priceWithoutVat$priceWithVat$vat 时,您有什么结果?你有数字吗?
  • @DamianDziaduch 不,他们都是PhpSpec\Wrapper\Collaborator class
  • 看起来是包中的问题。你绝对应该通过 GitHub 问题询问包作者/贡献者 :)

标签: php testing testng-dataprovider phpspec


【解决方案1】:

如果您的formatData 方法中的getAmountWithTax() 返回PhpSpec\Wrapper\Collaborator 的一个实例,则意味着它返回一个Prophecy 模拟构建器而不是实际的模拟,即您通过调用reveal() 方法获得的模拟。我不知道您的数据提供者是什么样子,但您似乎在模拟您的 Price 值对象而不是创建其真实实例,并且您的生产代码中的 $product->getPrice() 返回错误类型的对象。

解决方案是创建 Price 值对象的真实实例,该实例稍后由 $product->getPrice() 在数据提供程序中使用 new 返回,或者在该实例上调用 reveal(),如下所示(假设$price 是一个来自类型提示参数的模拟对象):

$product->getPrice()->willReturn($price->reveal());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多