2016-06-19 1 views
1

У меня есть услуга MoneyMover, которая меняет состояние двух объектов: уменьшает amount от sender и добавляет эту сумму в receiver.Как написать спецификацию для служб, которые изменяют состояние объекта?

У меня пока нет реализации. И в соответствии с BDD Я пишу спецификации для этой функции:

function it_should_reduce_balance_of_sender(User $sender, User $receiver) 
{ 
    $sender->getBalance()->willReturn(5); 
    $this->moveFromSenderToReciever($sender, $receiver, 5); 
    $sender->getBalance()->shouldReturn(0); 
} 

Но я могу только проверить состояние моей службы не каких-либо объектов пророчества, которые используются. И поэтому эта спецификация выдает фатальную ошибку:

Call to undefined method Prophecy\Prophecy\MethodProphecy::shouldReturn()

Как проверить состояние смены объекта?

Я знаю, что я могу использовать что-то вроде этого:

$sender->getBalance()->shouldBeCalled()->willReturn(5); 
$sender->setBalance(0)->shouldBeCalled(); 

$this->moveFromSenderToReceiver($sender, $reciever, 5); 

Но что, если я просто хочу, чтобы проверить, что состояние было изменено?

ответ

0

Ваше отвращение к его проверке таким образом не кажется слишком необоснованным. Но вместо того, чтобы пытаться сгибать phpspec по вашему желанию, возможно, более чистый способ решить это - избегать сеттеров & геттеров. Как насчет чего-то подобного?

$sender->decreaseBalanceBy(5)->shouldBeCalled(); 

$this->moveFromSenderToReceiver($sender, $reciever, 5); 

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

0

Вы нормально с

$sender->getBalance()->shouldBeCalled()->willReturn(5); 
$sender->setBalance(0)->shouldBeCalled(); 

$this->moveFromSenderToReceiver($sender, $reciever, 5); 

, что это правильный подход, как $sender и $receiver являются два сотрудника.

Вам нужно остановиться и подумать: что делает мой класс? если ваш ответ , изменяющий баланс конкретного пользователя, я боюсь, что это неправильный ответ (*).
Лучше всего: поведение вашего класса заключается в том, чтобы «отправить сообщение» или «передать ответственность» пользователю, заявив, что ему нужно установить баланс разницы. Вы совершенно безопасны здесь, говоря: «Хорошо, если я вызываю этот метод в своем классе, следует называть setBalance и getBalance (потому что это то, что должен делать ваш класс!).

Если вы хотите проверить правильность установки (или возврата) баланса, вы должны создать еще один класс спецификаций (который будет специфицировать ваш класс User) и выполнить все тесты, которые предоставят вам уверенное состояние с кодом ,

Таким образом, если оба теста зеленые, тогда вы можете спокойно полагаться на то, что вы написали.

Помните, что PHPSpec - это инструмент BDD, а не TDD, поэтому вам нужно сосредоточиться на таких вещах: «Каково поведение моего класса?» это вопрос.

Просто для полноты, подумайте о внешнем коде, который у вас нет, такой ORM o DBAL или что вы можете использовать для выполнения операций ввода-вывода с базой данных. Скажем, что у вас класс тестирование , описывающее, необходимо записать значения в базу данных: вы никогда не будете проверять, что фактические данные записаны.Вместо этого вы должны проверить, вызваны ли вызовы методов (такие write, read или какое бы имя они не были получены): если они есть, вы в порядке с ним, так как, надеюсь, ваша библиотека получила свои собственные тестовые пакеты, которые выполняют проверки о том, что представляет собой взаимодействие между их собственным кодом и базой данных.

(*) Это неправильный ответ, так как вы не напрямую звонок $user->amount = 0. Во-первых, это глупо, как amount, надеюсь, является частным членом класса User. Таким образом, вы просто передаете ответственность кому-то другому (класс User, где должна принадлежать логика). Конечно, на более высоком уровне абстракции, говоря, что ваш класс меняет баланс конкретного пользователя, все в порядке, здесь мне нужно было такое разделение, чтобы сосредоточить внимание читателя на другой точке зрения, которая действительно могла бы действительно помочь понять почему PHPSpec настолько ограничительна для такого рода операций, если вы делаете сравнение с другими инструментами, такими как PHPUnit или что-то еще.