Пример теста PHPSpec с Mock всегда возвращает ноль, но реализация работает как положено

Я хочу начать с PHPSpec, поэтому я работаю с двумя простыми классами. Первый отвечает за применение процентного уменьшения или увеличения к числу, а второй отвечает за расчет цены продукта с использованием процентного заявителя (например, макет).

PercentageToNumberApplyerSpec (spec):

namespace spec\My;

use PhpSpec\ObjectBehavior;
use Prophecy\Argument;

class PercentageToNumberApplyerSpec extends ObjectBehavior
{
function it_is_initializable()
{
$this->shouldHaveType('My\PercentageToNumberApplyer');
}

function it_enlarges_a_number_with_a_given_percentage()
{
$this->enlarge(100, 20)->shouldReturn(120);
$this->enlarge(80, 25)->shouldReturn(100);
$this->enlarge(20, 50)->shouldReturn(30);
}

function it_reduces_a_number_with_a_given_percentage()
{
$this->reduce(100, 20)->shouldReturn(80);
$this->reduce(80, 10)->shouldReturn(72);
$this->reduce(250, 20)->shouldReturn(200);
}
}

PercentageToNumberApplyer (реализация):

<?php

namespace My;

class PercentageToNumberApplyer
{
/**
* Enlarge given number with a given percentage
*
* @param $number
* @param $percentage
* @return float
*/
public function enlarge($number, $percentage)
{
return $this->calculate($number, $percentage) + $number;
}

/**
* Reduce given number with a given percentage
*
* @param $number
* @param $percentage
* @return mixed
*/
public function reduce($number, $percentage)
{
return $number - $this->calculate($number, $percentage);
}

/**
* @param $number
* @param $percentage
* @return float
*/
private function calculate($number, $percentage)
{
return $number * $percentage / 100;
}
}

PriceCalculatorSpec (spec):

<?php

namespace spec\My;

use My\PercentageToNumberApplyer;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;

class PriceCalculatorSpec extends ObjectBehavior
{
function let(PercentageToNumberApplyer $percentageToNumberApplyer)
{
$this->beConstructedWith($percentageToNumberApplyer);
}

function it_calculates_price_discount($percentageToNumberApplyer)
{
$number = 100;
$discount = 20;

$percentageToNumberApplyer->reduce($number, $discount)->shouldBeCalled();

$this->applyDiscountTo($number, $discount)->shouldReturn(80);
}
}

Эта проблема

Проблема в том, что в приведенном выше примере после запуска phpspec результат будет:

- it calculates price discount
expected [integer:80], but got null

PriceCalculator (реализация):

<?php

namespace My;

class PriceCalculator
{
/**
* @var PercentageToNumberApplyer
*/
private $percentageToNumberApplyer;

/**
* @param PercentageToNumberApplyer $percentageToNumberApplyer
*/
public function __construct(PercentageToNumberApplyer $percentageToNumberApplyer)
{
$this->percentageToNumberApplyer = $percentageToNumberApplyer;
}

/**
* @param $basePrice
* @param $discount
* @return mixed
*/
public function applyDiscountTo($basePrice, $discount)
{
return $this->percentageToNumberApplyer->reduce($basePrice, $discount);
}
}

Почему работает следующий вариант использования, даже если тест не пройден:

$priceCalculator = new \My\PriceCalculator(new \My\PercentageToNumberApplyer());

$price = $priceCalculator->applyDiscountTo(100, 20);

Цена $ имеет значение 80 …

0

Решение

Вам не нужно издеваться в вашем случае. Стаб будет делать. Читайте больше на тестовых двойниках в Тест PHP удваивает шаблоны с пророчеством.

Вместо насмешливого звонка:

$percentageToNumberApplyer->reduce($number, $discount)->shouldBeCalled();

Заглушка это:

$percentageToNumberApplyer->reduce($number, $discount)->willReturn(80);

Далее вам нужно только ожидать, что то, что рассчитано, действительно возвращается:

$percentageToNumberApplyer->reduce($number, $discount)->willReturn(80);

$this->applyDiscountTo($number, $discount)->shouldReturn(80);

Это потому, что вас не должно волновать, был ли сделан звонок. Вы заинтересованы только в результате.

Как правило, вы обычно:

  • издеваться над соавторами, которые выполняют действие (командные методы)
  • сотрудники-заглушки, которые возвращают что-то (методы запроса)

В большинстве случаев лучше иметь разделение между ними (разделение команд / запросов), и нам не нужно будет насмехаться и заглушки одновременно.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]