Как правильно тестировать подклассы с помощью phpspec dataprovider

#php #testing #testng-dataprovider #phpspec

#php #тестирование #testng-dataprovider #phpspec

Вопрос:

Я довольно новичок в тестировании 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
  

Если я жестко запрограммирую эти значения, то тест будет зеленым. Однако я хочу протестировать цены и результаты varios, поэтому я решил использовать dataProvider метод.
Но когда dataProvider передается $amountWithoutTax значение, это не строка, а PhpSpecWrapperCollaborator класс, и из-за этого bcmul происходит сбой.

Если я изменю $amountWithoutTax значение на $priceWithoutVat->getWrappedObject() , то DoublestdClassP97 класс будет передан, и из-за этого произойдет 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"
}
  

Комментарии:

1. Что у вас есть, когда вы var_dump $priceWithoutVat , $priceWithVat и $vat в самом тесте? У вас есть номера?

2. @DamianDziaduch Нет, они все PhpSpecWrapperCollaborator классные

3. Похоже, проблема в пакете. Вам обязательно следует задать вопросы автору пакета / участникам через GitHub 🙂

Ответ №1:

Если getAmountWithTax() в вашем formatData методе возвращается экземпляр PhpSpecWrapperCollaborator , это означает, что он возвращает макет Prophecy вместо фактического макета, то есть того, который вы получаете, вызывая reveal() метод. Я не знаю, как выглядит ваш поставщик данных, но, похоже, вы издеваетесь над своими Price объектами значений вместо того, чтобы создавать их реальные экземпляры, и $product->getPrice() в вашем производственном коде возвращается объект неправильного типа.

Решением было бы либо создать реальный экземпляр объекта Price value, который позже возвращается с помощью $product->getPrice() with new в поставщике данных, либо путем вызова reveal() для этого экземпляра, вот так (предполагая, что $price это макет объекта, который исходит из параметра с указанием типа):

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