function
() {
$order
=
new
Order();
$factory
=
new
InvoiceFactory();
$invoice
=
$factory
->
createFromOrder
(
$order
);
expect(
$invoice
)
->
to
->
be
->
instanceof
(
'CleanPhp\Invoicer\Domain\Entity\Invoice'
);
});
it(
'should set the total of the invoice'
,
function
() {
$order
=
new
Order();
$order
->
setTotal
(
500
);
$factory
=
new
InvoiceFactory();
$invoice
=
$factory
->
createFromOrder
(
$order
);
expect(
$invoice
->
getTotal
())
->
to
->
equal
(
500
);
});
it(
'should associate the Order to the Invoice'
,
function
() {
Building Our Domain
111
$order
=
new
Order();
$factory
=
new
InvoiceFactory();
$invoice
=
$factory
->
createFromOrder
(
$order
);
expect(
$invoice
->
getOrder
())
->
to
->
equal
(
$order
);
});
it(
'should set the date of the Invoice'
,
function
() {
$order
=
new
Order();
$factory
=
new
InvoiceFactory();
$invoice
=
$factory
->
createFromOrder
(
$order
);
expect(
$invoice
->
getInvoiceDate
())
->
to
->
loosely
->
equal
(
new
\DateTime());
});
});
});
Not only do we want our
InvoiceFactory
to return an instance of an
Invoice
object, but it
should also have its
$total
property set to the
$total
of the
Order
, as well as have the
Order
that it was generated for assigned to it, and finally, today’s date should be set as the
$invoiceDate
of the
Invoice
.
Now we have some pretty robust tests for what we want this factory to do! Let’s make these tests
pass now by filling out the rest of the
createFromOrder()
method:
public function
createFromOrder
(Order
$order
) {
$invoice
=
new
Invoice();
$invoice
->
setOrder
(
$order
);
$invoice
->
setInvoiceDate
(
new
\DateTime());
$invoice
->
setTotal
(
$order
->
getTotal
());
return
$invoice
;
}
And with that, our
InvoiceFactory
is now complete and its tests passing.
Writing tests in this manner allows us to quickly define the behavior of a class and flesh out how
it will work and relate to other objects. This falls into the realm of
Behavior-Driven Development
(BDD)³⁵
, which you can look into in more detail if it interests you. It goes hand-in-hand quite
well with Domain-Driven Development and Test-Driven Development.
³⁵
http://dannorth.net/introducing-bdd/
Building Our Domain
112
Peridot has a handy watcher plugin that allows for continuously running the tests as
you make changes. We can install it by running:
composer
require
--
dev peridot
-
php
/
peridot
-
watcher
-
plugin
After that, we’ll create a
peridot.php
file in the root directory that looks like:
// peridot.php
use
Evenement\EventEmitterInterface;
use
Peridot\Plugin\Watcher\WatcherPlugin;
return function
(EventEmitterInterface
$emitter
) {
$watcher
=
new
WatcherPlugin(
$emitter
);
$watcher
->
track
(__DIR__
.
'/src'
);
};
Now we can use the
--watch
flag to run the tests continuously!
./
vendor
/
bin
/
peridot specs
/ --
watch
Invoicing Service
The biggest piece of our domain logic in this application is the invoicing process. We’re going to
go collect all uninvoiced orders, once a month, and generate invoices for them. It’s our goal to do
this independently of any framework, library, or other external service. This way, we can ensure
that the core application is completely uncoupled from anything but itself, and it can easily be
dropped into any framework and perform it’s function.
This service is going to use the
OrderRepositoryInterface
to collect the orders to invoice, and
then use our
InvoiceFactory
to create the invoices for those orders. Let’s again start by writing
some tests to define these behaviors:
// specs/domain/service/invoice-factory.spec.php
describe(
'InvoicingService'
,
function
() {
describe(
'->generateInvoices()'
,
function
() {
it(
'should query the repository for uninvoiced Orders'
);
it(
'should return an Invoice for each uninvoiced Order'
);
});
});
Things are a little trickier this time. Since we haven’t written any concrete repositories yet, we
can’t use one to perform this test. Instead of writing and using a concrete repository, we’re going
to mock one using the Prophecy library.
Building Our Domain
113
Luckily, Peridot also comes with a plugin to make integrating those a piece of cake. Let’s install
it:
composer
require
--
dev peridot
-
php
/
peridot
-
prophecy
-
plugin
And then add it to our
peridot.php
file:
// peridot.php
Do'stlaringiz bilan baham: |