WEBVTT

NOTE Created by CaptionSync from Automatic Sync Technologies www.automaticsync.com

00:00:00.276 --> 00:00:03.426 align:middle
Hi everyone.

00:00:03.826 --> 00:00:06.416 align:middle
Welcome. Let's get started.

00:00:06.416 --> 00:00:09.506 align:middle
Maybe we can close the doors.

00:00:10.676 --> 00:00:18.046 align:middle
Hi. I'm Ciaran, and the subject of this talk
is Behat and the best practices around Behat.

00:00:18.076 --> 00:00:25.986 align:middle
I'm a consultant around areas like agile,
quality, communication in teams being productive

00:00:25.986 --> 00:00:31.006 align:middle
and most of the time the thing
I introduced to organizations

00:00:31.006 --> 00:00:33.466 align:middle
that helps them the most is this thing
called behavior driven development.

00:00:35.626 --> 00:00:40.366 align:middle
So generally in software we start with some
kind of problem maybe we express the problem

00:00:40.366 --> 00:00:43.926 align:middle
as a project goal or maybe you
express the problem as an epic.

00:00:44.476 --> 00:00:51.456 align:middle
We've got some sort of business problem that
we want to solve and we caught some ideas

00:00:51.846 --> 00:00:54.626 align:middle
about how we're going to solve these
problems and policies we're going to put

00:00:54.626 --> 00:00:58.376 align:middle
into place some things we're going to let
users do that they couldn't do before,

00:00:58.506 --> 00:01:00.486 align:middle
some things we're going to
stop people from doing.

00:01:00.526 --> 00:01:02.726 align:middle
We have we, we generate some
kind of business rules.

00:01:03.236 --> 00:01:12.486 align:middle
And then at some point we implement technical
solutions that implement those business rules

00:01:12.486 --> 00:01:15.836 align:middle
or enable those, those new policies
and we can launch the product

00:01:15.836 --> 00:01:17.146 align:middle
and real people can start using it.

00:01:18.226 --> 00:01:22.616 align:middle
And as we go through this progression from
that side to that side, when you're looking

00:01:22.616 --> 00:01:26.626 align:middle
at it that way, the cost gets higher.

00:01:27.306 --> 00:01:29.996 align:middle
So the cost of each of these things increases.

00:01:29.996 --> 00:01:30.646 align:middle
Having a ...

00:01:31.206 --> 00:01:32.926 align:middle
identifying a business problem is cheap.

00:01:32.926 --> 00:01:34.876 align:middle
Coming up with some ideas for how we solve it.

00:01:35.556 --> 00:01:36.766 align:middle
It's relatively cheap.

00:01:36.766 --> 00:01:41.056 align:middle
We have to talk to people and then technical
solutions and building stuff is expensive.

00:01:43.686 --> 00:01:49.316 align:middle
So shifting left is about maybe trying
a lot of BDD practice is about trying

00:01:49.316 --> 00:01:54.536 align:middle
to test these ideas earlier, testing
before we commit them into code.

00:01:55.166 --> 00:01:59.956 align:middle
So a lot of it is about communication, so
it's called behavior driven development,

00:02:00.006 --> 00:02:01.996 align:middle
Behat is a behavior driven development tool.

00:02:03.136 --> 00:02:08.966 align:middle
The name comes from behavior testing, but that's
not documented anywhere that I know about.

00:02:08.966 --> 00:02:11.236 align:middle
So it's a secret for you.

00:02:11.656 --> 00:02:16.666 align:middle
So, what's behavior Liz Keogh
says BDD is when you use examples

00:02:16.666 --> 00:02:18.476 align:middle
in conversations to illustrate behavior.

00:02:18.996 --> 00:02:21.836 align:middle
Just about having a conversation.

00:02:22.576 --> 00:02:24.696 align:middle
Number one, difficult for developers sometimes.

00:02:25.126 --> 00:02:28.106 align:middle
So we need people in the teams who
can enable this kind of process

00:02:28.106 --> 00:02:30.136 align:middle
and help break down some barriers.

00:02:30.896 --> 00:02:35.096 align:middle
We need to talk about behavior
or define behavior in a minute.

00:02:36.346 --> 00:02:40.696 align:middle
What, what should the system do, you
know, not, not the technical details,

00:02:40.756 --> 00:02:42.536 align:middle
how should it behave in different situations?

00:02:44.316 --> 00:02:45.846 align:middle
We use concrete examples.

00:02:45.926 --> 00:02:49.646 align:middle
We give very specific examples of how
it should behave in different cases

00:02:50.046 --> 00:02:51.286 align:middle
or talk about why that's important.

00:02:51.826 --> 00:02:55.166 align:middle
So what's an example?

00:02:55.166 --> 00:02:57.906 align:middle
An example is something that illustrates a rule.

00:02:59.286 --> 00:03:02.856 align:middle
So maybe the important thing is understanding
business rules, but the idea is we give examples

00:03:02.856 --> 00:03:05.906 align:middle
as a very efficient way of making sure
everyone understands them the same way.

00:03:07.296 --> 00:03:10.196 align:middle
So naturally in a conversation if
you don't understand something,

00:03:10.196 --> 00:03:12.806 align:middle
to ask for an example, a concrete real example.

00:03:14.506 --> 00:03:19.506 align:middle
So, we've got these business rules
we're going to implement and we're going

00:03:19.506 --> 00:03:21.036 align:middle
to illustrate them with examples.

00:03:21.036 --> 00:03:23.306 align:middle
Examples are going to help us
understand the business rules,

00:03:23.986 --> 00:03:27.266 align:middle
help us check that we all are
aligned on the same business rules.

00:03:27.936 --> 00:03:32.746 align:middle
They have some value in themselves,
but mostly it's to make sure we all,

00:03:32.846 --> 00:03:34.066 align:middle
we're all talking about the same thing.

00:03:36.016 --> 00:03:37.306 align:middle
So here's a business rule.

00:03:38.796 --> 00:03:41.616 align:middle
We charge our customers sales
at a tax rate of 20 percent.

00:03:41.776 --> 00:03:44.396 align:middle
Quite common in different countries to do this.

00:03:44.976 --> 00:03:46.766 align:middle
Put your hand up if you understand this rule.

00:03:47.726 --> 00:03:49.756 align:middle
Someone wrote that in a user story,

00:03:49.956 --> 00:03:53.806 align:middle
you'd kind of have no further
questions, you can just implement it.

00:03:54.376 --> 00:03:58.496 align:middle
So, but there's an argument that
sometimes a business rule is so obvious

00:03:58.496 --> 00:04:00.616 align:middle
that we don't have to really
have a conversation.

00:04:01.356 --> 00:04:04.876 align:middle
But an example is a really cheap
way, even with a simple rule

00:04:04.876 --> 00:04:06.766 align:middle
of just validating, yes, we understand.

00:04:07.776 --> 00:04:08.816 align:middle
We really did understand it.

00:04:08.816 --> 00:04:14.326 align:middle
So I might ask the developer
who's from the US and they say,

00:04:14.326 --> 00:04:15.676 align:middle
yeah, I understand this completely.

00:04:15.676 --> 00:04:20.826 align:middle
So something's price is $10, we
charge $10 and we had $2 tax.

00:04:20.826 --> 00:04:22.426 align:middle
So we take $12 from the customer.

00:04:24.656 --> 00:04:29.676 align:middle
Put your hands up people if that's what
you thought it meant, not everyone, right?

00:04:29.796 --> 00:04:34.596 align:middle
So even in a simple business rule, we can
have a misunderstanding about how it works.

00:04:35.086 --> 00:04:36.986 align:middle
We'll come back to that.

00:04:37.176 --> 00:04:41.936 align:middle
So the person on the left has, has
this idea in their head, this rule,

00:04:41.936 --> 00:04:47.916 align:middle
and if they just expressed the rule, they
explain the algorithm or the general policy

00:04:47.916 --> 00:04:52.696 align:middle
that covers lots of cases it's possible for
the person on the right to have a different,

00:04:52.696 --> 00:04:54.466 align:middle
entirely valid understanding of the same rule.

00:04:55.046 --> 00:04:59.246 align:middle
If instead they give concrete examples.

00:04:59.676 --> 00:05:04.126 align:middle
So this is the rule and that means in
this situation, this is what will happen.

00:05:04.806 --> 00:05:10.486 align:middle
It gives the other person, an opportunity
to kind of run those concrete examples

00:05:10.486 --> 00:05:11.896 align:middle
through their own understanding and say,

00:05:11.896 --> 00:05:14.226 align:middle
that's not what I thought would
happen in those situations.

00:05:14.306 --> 00:05:15.366 align:middle
Maybe my model's wrong.

00:05:16.816 --> 00:05:17.886 align:middle
Maybe I understand your model.

00:05:17.886 --> 00:05:20.926 align:middle
And the best thing that can happen is
then we have two way communication.

00:05:22.826 --> 00:05:26.676 align:middle
They say, okay, so in this situation, this, you
mean this is what will happen in this situation.

00:05:27.246 --> 00:05:32.296 align:middle
So both this is a kind of back and forth,
but both parties look at the concrete cases

00:05:32.296 --> 00:05:34.586 align:middle
and they say those concrete cases really match

00:05:34.586 --> 00:05:36.776 align:middle
with the way I understood this
thing we're talking about.

00:05:37.666 --> 00:05:41.096 align:middle
So that means I think the thing in my head
is the same as the thing in your head.

00:05:42.156 --> 00:05:44.796 align:middle
We can't validate that directly
without telepathy,

00:05:45.176 --> 00:05:48.896 align:middle
but concrete cases are giving
us a way to sort of check this.

00:05:52.266 --> 00:05:57.506 align:middle
So, in my sales tax example, if the
developer gives the example, I can say,

00:05:57.696 --> 00:05:59.756 align:middle
actually, no, that's not what I meant.

00:06:00.026 --> 00:06:04.756 align:middle
What I meant is if something's priced
at 10 pounds, we charge 10 pounds.

00:06:04.756 --> 00:06:10.776 align:middle
We just remember that some of it was tax because
in the business where we're operating in the UK,

00:06:10.776 --> 00:06:15.476 align:middle
all prices have to be inclusive of sales
tax, not, not exclusive of sales tax.

00:06:15.576 --> 00:06:18.516 align:middle
And I gave this example in another
country and they had a different system

00:06:19.456 --> 00:06:23.966 align:middle
where some stores showed it inclusive and
some stores, some stalls showed it exclusive.

00:06:23.966 --> 00:06:29.366 align:middle
So I built the system this way
and invested my time and effort

00:06:29.366 --> 00:06:31.426 align:middle
in the code implementing this business rule.

00:06:31.896 --> 00:06:37.366 align:middle
Or maybe it would only find out when
someone tests test the software,

00:06:37.366 --> 00:06:41.496 align:middle
does some user acceptance testing because maybe
my QA team had the same understanding I did.

00:06:44.936 --> 00:06:49.316 align:middle
We can validate that earlier just by giving an
example, give us an opportunity much earlier

00:06:49.316 --> 00:06:55.706 align:middle
in the process to, to catch these understanding
mismatches or, I'd say requirements mismatches.

00:06:55.786 --> 00:06:58.766 align:middle
But we're not on the same wavelength.

00:07:00.496 --> 00:07:09.696 align:middle
So examples are about behavior and you can kind
of, um, a really sort of computer sciencey way

00:07:09.696 --> 00:07:11.666 align:middle
of looking at behavior is
there's an input and an output.

00:07:11.986 --> 00:07:16.536 align:middle
So something happens and there's
an outcome, there's an action,

00:07:16.686 --> 00:07:21.086 align:middle
something that causes behavior, there's an
outcome that's the result of the behavior.

00:07:21.276 --> 00:07:28.556 align:middle
I buy a pair of Levi 501's and I'm
charged 32.99 in and out, right?

00:07:30.636 --> 00:07:32.596 align:middle
So, then maybe there's something missing here.

00:07:33.276 --> 00:07:36.346 align:middle
It's not obvious why that
action leads to that outcome.

00:07:37.046 --> 00:07:39.636 align:middle
It's not really obvious why that
product leads to that price.

00:07:43.286 --> 00:07:45.276 align:middle
We need this other thing called context.

00:07:45.276 --> 00:07:48.766 align:middle
Something that happened in the past is
a good way of thinking about context.

00:07:49.876 --> 00:07:54.496 align:middle
You can express context as like a
state, the state the system is in.

00:07:55.146 --> 00:07:59.276 align:middle
It can be really useful to think about context
as what are the things that happened in the past

00:07:59.316 --> 00:08:04.466 align:middle
that are affecting this outcome, especially
if you're doing event driven stuff.

00:08:05.156 --> 00:08:09.186 align:middle
So what happened in the past
that means I'm charged 32.99.

00:08:09.316 --> 00:08:11.976 align:middle
What happened was that they
were listed it in the system.

00:08:11.976 --> 00:08:16.846 align:middle
So someone administrator loaded that
product into the system and gave it a price,

00:08:17.966 --> 00:08:20.526 align:middle
and now that means when I purchase
them, I get charged this money.

00:08:21.766 --> 00:08:23.636 align:middle
Those three things are really all you need.

00:08:23.636 --> 00:08:25.346 align:middle
There's some sort of triggering event.

00:08:25.586 --> 00:08:32.376 align:middle
Triggering action is what should happen and
there's, you know, the minimum necessary context

00:08:32.376 --> 00:08:34.586 align:middle
to understand why that causes that.

00:08:35.276 --> 00:08:38.656 align:middle
So when you're talking about examples,
it's quite easy to capture them in,

00:08:38.656 --> 00:08:44.266 align:middle
in something like this format, you know,
little notes when you're talking about things.

00:08:44.436 --> 00:08:46.626 align:middle
And examples go through a kind of lifecycle.

00:08:46.626 --> 00:08:54.746 align:middle
Early on when we sort of starting to think about
our business rules, we can use examples as a way

00:08:54.746 --> 00:08:58.596 align:middle
of discovering potential rules as a way
of being quite concrete about the system.

00:08:59.406 --> 00:09:03.926 align:middle
Coming up with different
options, diverging, brainstorming.

00:09:04.416 --> 00:09:06.806 align:middle
We can come up with lots of examples
of how the system could operate.

00:09:06.806 --> 00:09:11.126 align:middle
At some point we're going to start narrowing
down which things are we actually going

00:09:11.126 --> 00:09:13.766 align:middle
to implement, which things are
we going to implement first?

00:09:13.916 --> 00:09:17.966 align:middle
Then the examples get more detailed
so early on in their lifecycle.

00:09:17.966 --> 00:09:21.566 align:middle
You can think of an example like the guy
goes into the store and buys a pair of jeans

00:09:21.566 --> 00:09:23.006 align:middle
and it gets charged the right price.

00:09:23.556 --> 00:09:26.666 align:middle
We just write that down or even
something shorter, you know,

00:09:27.046 --> 00:09:31.486 align:middle
Dan North came up with the Friends
episode naming where it's the one

00:09:31.486 --> 00:09:35.696 align:middle
where he buys the jeans and you can
just sort of stick on a sticky note

00:09:35.696 --> 00:09:39.656 align:middle
and keep it somewhere later on in
their lifecycle when we're closer

00:09:39.656 --> 00:09:44.336 align:middle
to implementing them technically we write
them out in more detail and as we'll see,

00:09:44.336 --> 00:09:45.596 align:middle
we're going to use them with Behat.

00:09:45.596 --> 00:09:49.146 align:middle
We're going to write them out in a
formalized way that the machine can read.

00:09:50.066 --> 00:09:52.646 align:middle
But you know, think of that as
an, as an evolution of an example

00:09:52.646 --> 00:09:55.886 align:middle
as it becomes more likely that we're going to
implement that example in our, in our project.

00:09:56.366 --> 00:10:04.416 align:middle
So once you've got some examples, you can enrich
them by asking a couple of angles of questions

00:10:04.416 --> 00:10:09.586 align:middle
that Liz Keogh, again named in a blog post.

00:10:10.536 --> 00:10:14.456 align:middle
I come back, I come back to this
naming because it's a good reminder

00:10:14.456 --> 00:10:15.426 align:middle
when you're having a conversation.

00:10:15.426 --> 00:10:19.396 align:middle
Have I asked about the context, so
is that, is there another context

00:10:19.396 --> 00:10:21.326 align:middle
where this action leads to a different outcome?

00:10:21.706 --> 00:10:25.926 align:middle
So if I've got this example here,
I can say, is there any situation

00:10:25.926 --> 00:10:29.556 align:middle
where I could buy these jeans
and I wouldn't pay 32.99?

00:10:30.406 --> 00:10:31.676 align:middle
That's a great open question.

00:10:31.676 --> 00:10:35.026 align:middle
In fact, that's not a very good open question.

00:10:35.026 --> 00:10:37.566 align:middle
It should be what are the situations

00:10:38.156 --> 00:10:40.116 align:middle
where I would buy these jeans
and pay a different amount?

00:10:40.846 --> 00:10:44.226 align:middle
Don't give an opportunity for no.

00:10:44.616 --> 00:10:46.056 align:middle
What situations are there?

00:10:46.056 --> 00:10:50.866 align:middle
So as soon as you start having this conversation
with a real person or a real group of people

00:10:50.866 --> 00:10:56.076 align:middle
and they're thinking about, you know, because
it's an example, we've got a real real product,

00:10:56.836 --> 00:10:59.796 align:middle
a real amount of cash, and they
think about the real situation.

00:11:00.726 --> 00:11:03.226 align:middle
They're not thinking about specification land.

00:11:04.466 --> 00:11:07.216 align:middle
They're thinking about a real store and
then they can come up with loads of stuff.

00:11:07.216 --> 00:11:10.926 align:middle
Yeah, maybe they're on sale, maybe the
person buying them is a member of staff

00:11:10.926 --> 00:11:13.686 align:middle
and they get the discount
up to a certain amount.

00:11:14.056 --> 00:11:16.356 align:middle
Maybe the jeans were damaged,
and they're refunded to stock.

00:11:17.536 --> 00:11:20.336 align:middle
So in those cases, what are
the different outcomes?

00:11:20.336 --> 00:11:23.736 align:middle
This is a whole discovery process
of coming up with new examples,

00:11:24.626 --> 00:11:28.036 align:middle
new requirements we didn't
know we had and it's great

00:11:28.036 --> 00:11:31.146 align:middle
that we're discovering them
now rather than after delivery.

00:11:31.856 --> 00:11:37.856 align:middle
The other kind of approach Liz
advocates is outcome questioning.

00:11:37.856 --> 00:11:42.146 align:middle
So we've got the context, we've got
the action, we've got an outcome.

00:11:42.236 --> 00:11:44.166 align:middle
Are there other outcomes we have to think about?

00:11:45.556 --> 00:11:56.286 align:middle
So in this Levi's example, apart from me
being charged some money, what else happens?

00:11:56.566 --> 00:12:01.276 align:middle
Again, this is where the flood of future
user stories, future requirements sort

00:12:01.276 --> 00:12:03.506 align:middle
of cracks open the can of worms opens.

00:12:06.266 --> 00:12:10.936 align:middle
I'm charged 32.99 and I get a
pair of these jeans sent to me,

00:12:10.936 --> 00:12:15.266 align:middle
dispatched through the packing
system and the warehouse,

00:12:15.266 --> 00:12:22.526 align:middle
has to know that we've got fewer jeans than
we had last a minute ago and probably a load

00:12:22.526 --> 00:12:24.666 align:middle
of other stuff, you know,
an invoice gets generated

00:12:24.666 --> 00:12:28.966 align:middle
and the marketing stats get updated
and blah blah, blah, blah, blah.

00:12:28.966 --> 00:12:31.976 align:middle
We discover the huge scope
that we didn't know existed.

00:12:32.606 --> 00:12:35.106 align:middle
This is the discovery phase is where
you're having these conversations.

00:12:35.106 --> 00:12:38.116 align:middle
So you're trying to do this
early in, in a very informal way.

00:12:41.636 --> 00:12:45.666 align:middle
And one way of having these
conversations that I do recommend

00:12:45.666 --> 00:12:48.836 align:middle
as a starting point is example mapping.

00:12:49.336 --> 00:12:53.636 align:middle
It's a sort of workshoppy format
involves sticky notes on a wall.

00:12:53.636 --> 00:12:58.566 align:middle
It's easy to get people doing it
rather than sitting everyone sitting

00:12:58.566 --> 00:13:00.936 align:middle
around typing things into a Google docs.

00:13:01.756 --> 00:13:07.836 align:middle
Or God forbid, a Jira ticket on a big screen,
around everyone sits around the table.

00:13:07.836 --> 00:13:09.456 align:middle
It's good to get people moving and doing stuff.

00:13:09.456 --> 00:13:14.236 align:middle
So Matt invented an example mapping three
or four years ago and blogged about it.

00:13:14.496 --> 00:13:17.426 align:middle
There's lots of other ways of doing this kind
of workshop, but this is a great formula.

00:13:18.346 --> 00:13:21.096 align:middle
So you take the feature you're talking
about and you stick it on the wall.

00:13:21.096 --> 00:13:24.786 align:middle
In this case, it's calculating
the price of a shopping basket.

00:13:26.036 --> 00:13:29.096 align:middle
We've realized that customers like
to know the price before they pay.

00:13:29.316 --> 00:13:36.136 align:middle
So we're going to talk about that
feature and you try and figure

00:13:36.136 --> 00:13:42.326 align:middle
out what are the business rules and you
lay them out in this horizontal dimension.

00:13:42.326 --> 00:13:50.496 align:middle
So we have to apply sales tax, above a
certain amount you get free delivery and then

00:13:51.676 --> 00:13:54.996 align:middle
as you're going through the rules, you try and
think of really concrete examples of each rule.

00:13:54.996 --> 00:13:59.926 align:middle
How many examples do we need to give for
someone to understand how the rule works?

00:14:00.766 --> 00:14:06.536 align:middle
If you have VAT being applied, I can
probably come up with an example.

00:14:06.736 --> 00:14:09.216 align:middle
If you buy this specific product,
this is how much you pay in tax

00:14:09.216 --> 00:14:11.016 align:middle
and maybe don't need any other examples.

00:14:11.016 --> 00:14:12.706 align:middle
I don't need to generate
lots of different examples

00:14:12.706 --> 00:14:16.546 align:middle
because it's a simple rule,
free delivery above a threshold.

00:14:16.546 --> 00:14:19.476 align:middle
If you pay 50 pounds, you
don't pay any shipping.

00:14:19.476 --> 00:14:22.086 align:middle
If you pay 10 pounds, you pay some amount.

00:14:23.246 --> 00:14:25.556 align:middle
I don't have to put all the detail
when you're sticking these on the wall,

00:14:25.556 --> 00:14:29.966 align:middle
but kind of identifying which examples we're
going to have to go into detail on later.

00:14:29.966 --> 00:14:33.066 align:middle
We might have some questions.

00:14:33.066 --> 00:14:36.996 align:middle
So someone in this conversation says
like, what if you're shipping to Belgium

00:14:37.186 --> 00:14:39.116 align:middle
and our stores is in the United Kingdom?

00:14:39.326 --> 00:14:39.926 align:middle
What happens then?

00:14:39.926 --> 00:14:45.046 align:middle
We can capture the question as part of
the example map and actually what happens,

00:14:45.546 --> 00:14:47.426 align:middle
what happens with tax and
what happens with delivery.

00:14:48.836 --> 00:14:49.466 align:middle
We don't know.

00:14:49.646 --> 00:14:57.206 align:middle
If someone knows the answer for delivery, they
can say, okay, overseas shipping is a fixed rate

00:14:57.206 --> 00:15:00.806 align:middle
in each country and we don't have this concept
of a maximum amount where you get free shipping.

00:15:01.366 --> 00:15:07.396 align:middle
But maybe we end the session with a
question, how does tax work across borders?

00:15:07.396 --> 00:15:09.026 align:middle
Maybe we have to ask someone else who isn't

00:15:09.026 --> 00:15:15.406 align:middle
in this session before we can
proceed as a good example mapping.

00:15:16.376 --> 00:15:19.306 align:middle
I spend about 15 to 20 minutes
talking about a feature.

00:15:19.306 --> 00:15:26.046 align:middle
More than that then you're probably
going into more detail than you need to.

00:15:26.306 --> 00:15:29.306 align:middle
The questions at the end are, can we
start work on it without this answer?

00:15:30.986 --> 00:15:35.296 align:middle
Maybe that's something we trust we'll
find out during the sprint, you know,

00:15:36.256 --> 00:15:37.756 align:middle
or do we need to resolve it first?

00:15:37.756 --> 00:15:40.096 align:middle
Do we need to get an answer
before we say we can work on it.

00:15:41.186 --> 00:15:45.266 align:middle
More interestingly, can we do part of this
feature that doesn't involve the question

00:15:46.106 --> 00:15:48.366 align:middle
and a nice way to split is against these rules

00:15:48.366 --> 00:15:55.746 align:middle
so we can potentially take this overseas
shipping and move it into a new feature.

00:15:55.746 --> 00:15:59.986 align:middle
I'm going to say, okay, well we can
build the shopping basket pricing.

00:15:59.986 --> 00:16:03.786 align:middle
It'll only work in the UK and if
you select the different country,

00:16:03.786 --> 00:16:05.066 align:middle
we just don't show you the total.

00:16:05.696 --> 00:16:06.466 align:middle
We'll do that next week.

00:16:06.926 --> 00:16:10.776 align:middle
This can be a really useful way of
you know splitting down stories.

00:16:12.516 --> 00:16:14.266 align:middle
Example mapping is one technique.

00:16:14.476 --> 00:16:18.206 align:middle
You can do it one on one it's
good to do it in a, in a group.

00:16:18.206 --> 00:16:19.296 align:middle
I quite like doing it.

00:16:19.296 --> 00:16:21.936 align:middle
If you've got a few features to talk
about I quite like putting them physically

00:16:21.936 --> 00:16:25.816 align:middle
in different places in a room and people
rotate around them in a round robin.

00:16:26.956 --> 00:16:27.716 align:middle
It should be quick.

00:16:27.716 --> 00:16:28.746 align:middle
It should be scrappy.

00:16:29.066 --> 00:16:31.076 align:middle
You're not getting into loads
of detail on the examples.

00:16:31.076 --> 00:16:34.346 align:middle
You're just kind of identifying
hey we need to have an example

00:16:34.346 --> 00:16:35.656 align:middle
where someone gets free shipping.

00:16:37.556 --> 00:16:39.556 align:middle
There are other techniques
that are worth looking at.

00:16:39.556 --> 00:16:42.806 align:middle
Feature mapping is very similar
to example mapping,

00:16:42.806 --> 00:16:46.086 align:middle
but it adds a kind of time line concept.

00:16:47.086 --> 00:16:51.186 align:middle
So you have business rules, examples
and then steps in the process.

00:16:51.836 --> 00:16:54.816 align:middle
And of course if you're doing event
storming, they don't do event storming?

00:16:54.816 --> 00:17:00.976 align:middle
If you're doing event storming off of the
output of that as well as being super useful.

00:17:00.976 --> 00:17:06.226 align:middle
You can zoom in on sections around the commands
and say, given these events in the past

00:17:06.226 --> 00:17:08.616 align:middle
when this command happens,
these new events should happen.

00:17:09.176 --> 00:17:12.426 align:middle
You can sort of extract scenarios from that.

00:17:12.526 --> 00:17:13.976 align:middle
So let's talk about BDD.

00:17:13.976 --> 00:17:19.256 align:middle
That's some of the most important
stuff in bdd is discovery.

00:17:20.406 --> 00:17:22.246 align:middle
That's where you should start
if you're implementing BDD.

00:17:22.246 --> 00:17:26.836 align:middle
It's not really about testing, it's
also not about one way conversations.

00:17:26.836 --> 00:17:31.776 align:middle
I'm not suggesting that your product owner
does this kind of example mapping session,

00:17:31.776 --> 00:17:34.856 align:middle
identifies a load of examples and then
types them into Jira and then delivers it

00:17:34.856 --> 00:17:36.696 align:middle
to a team, who's never seen them before.

00:17:36.926 --> 00:17:40.396 align:middle
It's about having multiple
stakeholders inside those conversations.

00:17:43.586 --> 00:17:49.856 align:middle
But where it comes into testing is that once
you've got these examples, and we generated them

00:17:49.856 --> 00:17:56.096 align:middle
so everyone understood what we're building,
they are super useful for validating features.

00:17:56.856 --> 00:17:59.176 align:middle
Once we've built the feature,
we've now got a set

00:17:59.176 --> 00:18:01.586 align:middle
of concrete examples of how
the system should behave.

00:18:01.996 --> 00:18:03.386 align:middle
Even if we're doing manual testing.

00:18:03.906 --> 00:18:04.816 align:middle
That's really useful.

00:18:04.816 --> 00:18:06.956 align:middle
I know that if I buy an item
that costs 10 pounds,

00:18:06.956 --> 00:18:09.196 align:middle
I should be charged two pounds sales tax.

00:18:10.156 --> 00:18:13.336 align:middle
I can go into the system and buy
something that costs 10 pounds and I check,

00:18:13.336 --> 00:18:16.016 align:middle
I get charged two pounds sales tax.

00:18:16.716 --> 00:18:21.756 align:middle
So once we started to build the technical
solution, we're going to write tests

00:18:21.916 --> 00:18:25.296 align:middle
and these examples are going to be
very useful to create test cases.

00:18:25.776 --> 00:18:28.876 align:middle
This is where Behat fits in.

00:18:29.376 --> 00:18:35.476 align:middle
We've had a lot of rich conversation
conversations about what we're going to build.

00:18:36.156 --> 00:18:42.136 align:middle
I'm going to write some automated tests and
there's a, there's an overlap there where a tool

00:18:42.136 --> 00:18:47.316 align:middle
that can take written examples and help you
automate them into test is going to add value.

00:18:47.836 --> 00:18:51.526 align:middle
First tool like this was
called cucumber in Ruby.

00:18:52.476 --> 00:18:55.876 align:middle
Every language has a tool like this.

00:18:55.876 --> 00:19:02.776 align:middle
We tend to call them cucumbers, Behat
is sort of retaining it's own identity

00:19:02.776 --> 00:19:05.236 align:middle
because it's a completely separate code base.

00:19:05.306 --> 00:19:10.836 align:middle
It was never like a port, but we collaborate
a lot with the other cucumber tools

00:19:10.836 --> 00:19:17.226 align:middle
or we make sure their syntaxes are
interoperable and stuff like that.

00:19:18.656 --> 00:19:20.336 align:middle
So I wrote out an example.

00:19:20.736 --> 00:19:21.886 align:middle
You don't need to be able to read this.

00:19:22.686 --> 00:19:31.776 align:middle
I write out an example in a format called
Gherkin because it's from cucumber.

00:19:31.846 --> 00:19:36.036 align:middle
There is the same format we
were capturing on the cards.

00:19:36.156 --> 00:19:39.506 align:middle
You know, the three steps, the
context, the action, and the outcome.

00:19:39.986 --> 00:19:42.596 align:middle
It's just written out in a
way that is machine parseable,

00:19:42.766 --> 00:19:44.206 align:middle
but it's meant to be business readable.

00:19:44.206 --> 00:19:46.446 align:middle
So a human can read it as if it was a document.

00:19:46.966 --> 00:19:49.076 align:middle
Let's zoom in.

00:19:49.076 --> 00:19:51.286 align:middle
The problem I'm talking about
is scheduling training.

00:19:51.286 --> 00:19:55.286 align:middle
I do a lot of training and either we have
a training course with not enough people,

00:19:55.286 --> 00:19:58.526 align:middle
so we need to cancel it or
we have too many people.

00:19:59.116 --> 00:20:02.556 align:middle
So as a trainer I should be able to
cancel courses or schedule new ones

00:20:02.756 --> 00:20:04.306 align:middle
and I can identify the business rules.

00:20:04.576 --> 00:20:11.386 align:middle
This stuff at the top of the feature file is
just human readable text to explain to a person.

00:20:12.566 --> 00:20:19.346 align:middle
So the rules are, when I make a course, it
has size limits, there's a sort of threshold

00:20:19.346 --> 00:20:24.226 align:middle
where the course becomes viable, and
when we reach a maximum class size,

00:20:24.226 --> 00:20:25.716 align:middle
you can't sign up to that course anymore.

00:20:26.056 --> 00:20:29.136 align:middle
And then I come up with some
examples and I write them out.

00:20:29.816 --> 00:20:34.636 align:middle
The Background is context that's common
to all of the examples in the file.

00:20:35.226 --> 00:20:41.406 align:middle
So we talk about context using the Given
keyword: Given "BDD for Beginners" was proposed

00:20:41.406 --> 00:20:43.946 align:middle
with a class size of 2 to 3
people So that's the context.

00:20:44.446 --> 00:20:49.086 align:middle
The first example is, a course doesn't
get enough enrollments so it's not viable.

00:20:50.036 --> 00:20:55.476 align:middle
When only Alice enrolls in the course, then
this course won't be viable, easy to understand.

00:20:55.476 --> 00:20:55.986 align:middle
Hopefully.

00:20:56.066 --> 00:21:01.146 align:middle
This is an example where the
course gets enough enrollments.

00:21:01.146 --> 00:21:03.746 align:middle
So Alice is already enrolled in
the course, that's the context.

00:21:04.836 --> 00:21:06.526 align:middle
When Bob enrolls, that's the action.

00:21:06.756 --> 00:21:10.326 align:middle
Then the course becomes viable,
the course will be viable

00:21:10.966 --> 00:21:14.656 align:middle
because it was proposed to
the size of two to three.

00:21:14.656 --> 00:21:16.816 align:middle
And enrollments have stopped
when the class size is reached.

00:21:17.326 --> 00:21:19.866 align:middle
Given that Alice, Bob and Charlie
have already enrolled in the course,

00:21:19.866 --> 00:21:26.806 align:middle
when Derek tries to enroll in
the course, he can't enroll.

00:21:29.006 --> 00:21:32.726 align:middle
It costs something to write them out
in this detailed format and think

00:21:32.726 --> 00:21:34.316 align:middle
about how much detail you're gonna include.

00:21:35.556 --> 00:21:37.936 align:middle
So you have a kind of scrappy
conversation about examples.

00:21:38.736 --> 00:21:41.906 align:middle
When you're going to build the system soon you
write them out in this kind of Given, When,

00:21:41.906 --> 00:21:45.086 align:middle
Then format and you show them to the
person you had the conversation with

00:21:45.086 --> 00:21:46.556 align:middle
and says, this is what we talked about.

00:21:47.806 --> 00:21:50.606 align:middle
So whoever learned the most in the
conversation can write out these scenarios,

00:21:51.276 --> 00:21:53.406 align:middle
so this is what we talked about in the room.

00:21:53.406 --> 00:21:54.196 align:middle
Please validate that.

00:21:54.196 --> 00:21:55.536 align:middle
Let's just double check.

00:21:55.536 --> 00:22:02.126 align:middle
You don't do this, you don't write them out
in this detail in advance for everything.

00:22:03.536 --> 00:22:10.866 align:middle
The job of Behat is to take these multiple
feature files which have steps - a step is:

00:22:10.866 --> 00:22:16.096 align:middle
Given, When, Then - and somehow
execute them as tests.

00:22:17.406 --> 00:22:19.446 align:middle
And yeah, that's hard to execute as a test.

00:22:19.446 --> 00:22:20.246 align:middle
It needs some help.

00:22:20.696 --> 00:22:25.336 align:middle
So the help is that we have a
bunch of classes called contexts

00:22:25.766 --> 00:22:30.036 align:middle
with methods in, called step definitions.

00:22:31.326 --> 00:22:36.036 align:middle
Each one of these step definitions tells
Behat when you see a line like this

00:22:36.166 --> 00:22:38.726 align:middle
in the feature file, this is how you test it.

00:22:41.296 --> 00:22:45.216 align:middle
In the Gherkin file, Given a
thing happens to Ciaran and then

00:22:45.216 --> 00:22:51.816 align:middle
in the PHP file I'll write a method with
a doc block that has a pattern in it.

00:22:52.566 --> 00:22:55.956 align:middle
Then Behat will know, whenever I see a line
like that, I should execute that function.

00:22:55.956 --> 00:22:58.166 align:middle
And you'll see the function is parameterized.

00:22:59.346 --> 00:23:02.336 align:middle
So given a thing happens to Bob,
we'll also hit the same function.

00:23:03.216 --> 00:23:07.366 align:middle
And I have to write the test code inside that
function that's going to check the system.

00:23:08.776 --> 00:23:13.406 align:middle
The way a lot of users interact
with your system is through a UI

00:23:13.406 --> 00:23:15.526 align:middle
so it can be tempting to test through the UI.

00:23:16.036 --> 00:23:19.926 align:middle
It's normally a much better idea
to test through a domain model.

00:23:20.626 --> 00:23:23.546 align:middle
So why is that?

00:23:23.546 --> 00:23:29.896 align:middle
Testing through the UI is going to be slow,
you have to automate a browser, things break,

00:23:30.836 --> 00:23:34.586 align:middle
web servers time out, that kind of stuff.

00:23:34.926 --> 00:23:38.676 align:middle
And if I just test through
the UI, all that tells me is

00:23:38.676 --> 00:23:42.026 align:middle
that the UI supports all the business rules.

00:23:42.546 --> 00:23:46.566 align:middle
That means the business rules
could be living inside a controller

00:23:46.566 --> 00:23:51.626 align:middle
or the business rules could be living inside a
Twig template because we didn't put the button

00:23:51.626 --> 00:23:53.706 align:middle
on that template and that means
people can't do that thing.

00:23:53.706 --> 00:23:57.766 align:middle
We probably want to check that the
domain model is supporting these things.

00:23:58.456 --> 00:23:59.846 align:middle
So let's see how that looks.

00:24:01.916 --> 00:24:08.316 align:middle
So by driving PHP objects directly from my
scenario, it's going to prove my php objects,

00:24:08.316 --> 00:24:09.806 align:middle
implement the business rules correctly.

00:24:10.376 --> 00:24:17.216 align:middle
It's going to give a bit of a pressure to
use the same naming from the feature file

00:24:17.626 --> 00:24:19.806 align:middle
in the objects because I'm
looking at both at the same time.

00:24:19.806 --> 00:24:22.586 align:middle
And I'm not going to pick a different
word when I can use the same word.

00:24:22.586 --> 00:24:24.576 align:middle
And it's gonna run fast.

00:24:24.576 --> 00:24:28.346 align:middle
It's going to run almost as fast as your
unit tests because it's just running PHP.

00:24:29.756 --> 00:24:33.776 align:middle
So when I execute that feature file in
Behat, you'll see they all get this nice,

00:24:34.036 --> 00:24:38.186 align:middle
maybe it hasn't come across, nice
yellow color and maybe you see

00:24:38.186 --> 00:24:40.366 align:middle
at the bottom everything is undefined.

00:24:40.476 --> 00:24:47.356 align:middle
So Behat is telling me, "you need to tell
me how to test all of these steps.". So I go

00:24:47.356 --> 00:24:53.836 align:middle
through my feature, I start at the top,
here, I look at the first one, this one.

00:24:55.196 --> 00:24:58.956 align:middle
Given BDD for beginners was proposed
with a class size of two to three people

00:24:58.956 --> 00:25:03.866 align:middle
and then I write a method in
my context class annotated

00:25:03.866 --> 00:25:05.706 align:middle
with something that's going
to match that pattern.

00:25:05.706 --> 00:25:08.826 align:middle
And I think, what do I want this to look like?

00:25:09.426 --> 00:25:13.846 align:middle
This is where I start, this is
the TDD like loop I go through.

00:25:13.846 --> 00:25:16.186 align:middle
I'm going to start here.

00:25:16.186 --> 00:25:19.126 align:middle
So there's a thing called a course.

00:25:19.486 --> 00:25:22.336 align:middle
So I'll make an object, I'll pretend
there's a class called a course.

00:25:22.596 --> 00:25:24.646 align:middle
I'm going to give it a constructor
called propose()

00:25:24.646 --> 00:25:27.476 align:middle
because the word propose
was in the example I wrote.

00:25:28.646 --> 00:25:34.396 align:middle
And it's proposed with a class size
of between a minimum and a maximum.

00:25:34.396 --> 00:25:40.186 align:middle
So, I kind of create, I guess course is an
entity and class size is like a value object.

00:25:41.666 --> 00:25:43.296 align:middle
And I want to execute it.

00:25:43.296 --> 00:25:45.606 align:middle
I get an error because none
of these classes exist.

00:25:46.436 --> 00:25:49.876 align:middle
I kind of started here, I'm using
the domain language from the example

00:25:50.026 --> 00:25:54.976 align:middle
in my code and I like to see the red.

00:25:55.596 --> 00:25:59.486 align:middle
If if the first time you
run the tests, it's green,

00:26:00.406 --> 00:26:03.626 align:middle
there's a lot of things you could have done
wrong, so it's always good to run the test

00:26:03.626 --> 00:26:07.126 align:middle
and see them red and then you write the
code that makes them go from red to green.

00:26:07.666 --> 00:26:10.066 align:middle
So, I have to do some stuff here.

00:26:10.066 --> 00:26:13.446 align:middle
It's a short talk so you
have to make these objects

00:26:13.446 --> 00:26:15.886 align:middle
and you probably write some unit
tests for those objects as well.

00:26:17.256 --> 00:26:21.576 align:middle
And you know if you're super advanced you write
the unit tests first and all that good stuff,

00:26:22.456 --> 00:26:25.596 align:middle
but at some point I've written a
course object that has a constructor

00:26:26.136 --> 00:26:30.486 align:middle
and I've written a class size object that has
a constructor and I did some extra thinking

00:26:30.486 --> 00:26:33.406 align:middle
about what do I need to check
inside class sizes.

00:26:33.406 --> 00:26:36.076 align:middle
Maybe I'd check that max is bigger than the min.

00:26:36.446 --> 00:26:39.246 align:middle
So, there's extra stuff I have to think
about as I'm building these objects,

00:26:39.316 --> 00:26:41.816 align:middle
as soon as they exist Behat starts passing.

00:26:43.276 --> 00:26:47.816 align:middle
So, the next step only Alice
enrolls in this course.

00:26:48.696 --> 00:26:53.966 align:middle
In the previous step, I sort of
stored the course that I was creating

00:26:54.206 --> 00:26:56.606 align:middle
as a member variable in the context.

00:26:58.156 --> 00:27:05.776 align:middle
The next step, Alice enrolls in this course,
I'm going to enroll a learner on a course.

00:27:06.306 --> 00:27:09.146 align:middle
Um, there's an example here of a transformation.

00:27:09.506 --> 00:27:14.356 align:middle
So Behat does support very simple
transformations from strings to value objects,

00:27:14.356 --> 00:27:19.316 align:middle
especially if we're going to be using the
same sort of values in a lot of your examples.

00:27:19.356 --> 00:27:27.426 align:middle
So whenever I see a name, a learner, I'm going
to turn the string into a learner object.

00:27:27.616 --> 00:27:30.186 align:middle
The course, gets an enroll method.

00:27:30.676 --> 00:27:36.406 align:middle
I have to then add an enroll method to
the course that takes a learner object.

00:27:36.406 --> 00:27:39.076 align:middle
I have to create a learner value object,
write unit tests, blah, blah, blah.

00:27:39.596 --> 00:27:43.356 align:middle
Then this step will start to pass.

00:27:44.086 --> 00:27:45.586 align:middle
Then the course will not be viable.

00:27:46.606 --> 00:27:48.416 align:middle
So I need to write a step that checks that

00:27:49.616 --> 00:27:54.146 align:middle
and I'm using an assertion
here, I'm using a PHP assertion.

00:27:54.196 --> 00:27:57.626 align:middle
Any step that doesn't throw an
exception is considered a pass.

00:27:58.696 --> 00:28:03.826 align:middle
So in the Then steps you have to check
something, Then the course will not be viable.

00:28:03.826 --> 00:28:06.516 align:middle
I have to tell Behat this is how you
check the course won't be viable.

00:28:06.576 --> 00:28:08.426 align:middle
You can use a different assertion library.

00:28:08.426 --> 00:28:13.586 align:middle
You can use the PHPUnit assertion library,
that has a bit of extra support than Behat

00:28:13.626 --> 00:28:16.966 align:middle
because we know how to get the better error
message out of those kinds of exceptions.

00:28:17.676 --> 00:28:19.626 align:middle
Or you can have an if statement
that throws your own exception.

00:28:19.926 --> 00:28:22.686 align:middle
It is kind of up to you.

00:28:22.786 --> 00:28:25.016 align:middle
So I'm asserting this is viable
method that returns false.

00:28:25.406 --> 00:28:30.216 align:middle
I have to then write some code,
some logic when I've done all

00:28:30.306 --> 00:28:32.486 align:middle
of that, my first scenario is passing.

00:28:32.486 --> 00:28:37.676 align:middle
And actually that's quite
a good point to commit.

00:28:38.196 --> 00:28:41.616 align:middle
I built all the objects and
implemented one of the scenarios

00:28:41.616 --> 00:28:45.246 align:middle
and working per scenario is
actually very nice as a developer.

00:28:45.876 --> 00:28:48.146 align:middle
It's a good way of not trying
to think of everything at once.

00:28:49.436 --> 00:28:51.416 align:middle
So what's next?

00:28:51.416 --> 00:28:55.416 align:middle
I do all of the other scenarios, I work
my way through in the same sort of way.

00:28:55.936 --> 00:28:59.476 align:middle
So you can kind of imagine Alice
is already enrolled in the course.

00:28:59.476 --> 00:29:00.786 align:middle
I call the existing enroll method.

00:29:01.516 --> 00:29:03.866 align:middle
Bob enrolls in the course I
call the existing enroll method.

00:29:05.186 --> 00:29:06.306 align:middle
The course will be viable.

00:29:06.406 --> 00:29:07.826 align:middle
I assert something slightly different.

00:29:07.966 --> 00:29:08.996 align:middle
I assert it's not viable.

00:29:10.296 --> 00:29:13.976 align:middle
And, you know, the third scenario,
Derek tries to enroll in the course.

00:29:13.976 --> 00:29:18.296 align:middle
Maybe I catch an exception, then
he should not be able to enroll.

00:29:18.296 --> 00:29:20.076 align:middle
I maybe check the exception got thrown,

00:29:20.076 --> 00:29:23.406 align:middle
or I check the course doesn't
have Derek as a as an attendee.

00:29:23.896 --> 00:29:26.186 align:middle
So I validated all of this inside my objects.

00:29:28.056 --> 00:29:29.776 align:middle
That doesn't take long.

00:29:29.776 --> 00:29:33.906 align:middle
If you look at the execution time and
the screenshot, maybe that's a lie.

00:29:34.106 --> 00:29:37.246 align:middle
It's twenty it's still the same 20
milliseconds to run those three scenarios.

00:29:37.246 --> 00:29:38.336 align:middle
That's not unrealistic.

00:29:39.216 --> 00:29:41.706 align:middle
They're like large unit tests.

00:29:42.996 --> 00:29:47.856 align:middle
There aren't, there's no infrastructure
involved, nothing crazy is happening.

00:29:47.856 --> 00:29:50.476 align:middle
We're just checking that these objects
have the business rules in them

00:29:50.476 --> 00:29:52.126 align:middle
and that's a super powerful place to start.

00:29:53.916 --> 00:29:59.056 align:middle
Actually talking about what the business rules
are, is a really powerful place to start.

00:29:59.136 --> 00:30:02.426 align:middle
But checking that the object objects implement
them on their, on their own and it's not,

00:30:02.526 --> 00:30:08.126 align:middle
you know, in a stored procedure or a controller
or somewhere else is really going to help

00:30:08.126 --> 00:30:11.926 align:middle
when you have to write a command line, a cron
job that also enrolls people, for instance.

00:30:13.456 --> 00:30:15.186 align:middle
The next layer to look at is the service layer.

00:30:16.116 --> 00:30:19.726 align:middle
And I'm not specifically
talking about Symfony services.

00:30:21.246 --> 00:30:26.336 align:middle
Quite often you have some layer in between
your domain model and your user interface,

00:30:27.496 --> 00:30:32.886 align:middle
and in the Symfony case it is Symfony services.

00:30:32.886 --> 00:30:39.826 align:middle
So when, you probably don't
want to be interacting directly

00:30:39.826 --> 00:30:41.566 align:middle
with these domain objects too much

00:30:41.566 --> 00:30:44.006 align:middle
in your controllers you want
to delegate it into services.

00:30:44.556 --> 00:30:50.776 align:middle
So, we, we might want to inject our
services into the Behat context.

00:30:51.396 --> 00:30:58.286 align:middle
As soon as you go into a Symfony app and you
start thinking about your Symfony services as.

00:30:59.476 --> 00:31:05.046 align:middle
So indeed, you would try and have your own
concept of application services and not tie it

00:31:05.046 --> 00:31:07.116 align:middle
into the Symfony service
container, but a lot of apps,

00:31:07.116 --> 00:31:08.806 align:middle
it is tied into the Symfony service container.

00:31:09.656 --> 00:31:11.816 align:middle
So it's really convenient to have a way

00:31:11.816 --> 00:31:15.256 align:middle
of accessing our services our
defined services from inside Behat.

00:31:16.366 --> 00:31:21.346 align:middle
And then trying to use the services rather
than using the domain model directly.

00:31:21.846 --> 00:31:25.856 align:middle
This is going to make sure that
our service layer supports all

00:31:25.856 --> 00:31:29.456 align:middle
of the use cases we want to support.

00:31:30.596 --> 00:31:34.386 align:middle
Even though the domain model is quite complex,
we can have a defined set of use cases.

00:31:34.786 --> 00:31:36.906 align:middle
These are the things that our system supports.

00:31:38.156 --> 00:31:45.216 align:middle
And you can test the same scenarios in multiple
ways using Behat, using a concept called suites.

00:31:45.606 --> 00:31:50.206 align:middle
So we wrote one context that told Behat how to
test every step directly against the objects.

00:31:50.656 --> 00:31:54.646 align:middle
You can define a separate suite that
tells Behat how to test the same steps

00:31:54.876 --> 00:31:57.866 align:middle
against a different layer of your
application, in this case services.

00:31:58.396 --> 00:32:01.196 align:middle
So it looks slightly different.

00:32:01.196 --> 00:32:05.566 align:middle
It's the same process for me when I
want to implement this first step,

00:32:05.686 --> 00:32:11.096 align:middle
BDD for Beginners was proposed with
a class size of two to three people.

00:32:11.096 --> 00:32:19.736 align:middle
Instead of creating, instead of creating domain
objects directly, I'm making calls to services.

00:32:19.736 --> 00:32:26.706 align:middle
So I'm saying course enrollments,
propose a course with a string name

00:32:27.436 --> 00:32:29.116 align:middle
and the minimum and maximum attendees.

00:32:30.226 --> 00:32:34.356 align:middle
So I'm kind of assuming that
course enrollments is available.

00:32:34.966 --> 00:32:37.056 align:middle
There's a service called the
course enrollment service.

00:32:38.046 --> 00:32:38.846 align:middle
Where's that come from?

00:32:38.846 --> 00:32:41.616 align:middle
You sort of see it, it's arriving
magically in the constructor.

00:32:42.276 --> 00:32:45.956 align:middle
And this is then becomes framework specific.

00:32:45.956 --> 00:32:55.186 align:middle
How is Behat accessing that service, the
Symfony 2 extension, which needs to be renamed

00:32:56.006 --> 00:33:03.436 align:middle
but it was a really good idea at the time to
call it that, will inject your Symfony services.

00:33:03.936 --> 00:33:11.566 align:middle
So, it takes care of finding your kernel,
bootstrapping the kernel, telling the kernel

00:33:11.566 --> 00:33:12.946 align:middle
that it's in the test environment.

00:33:12.946 --> 00:33:14.026 align:middle
You can override these things.

00:33:14.556 --> 00:33:24.236 align:middle
And then when we, instead of just listing the
the object, instead of just giving the name

00:33:24.236 --> 00:33:28.306 align:middle
of our service, our context
object, we also can inject param,

00:33:28.636 --> 00:33:32.706 align:middle
inject services as arguments to that context.

00:33:33.066 --> 00:33:36.276 align:middle
So in this case I'm saying there's an argument,
there's an argument called course enrollments

00:33:36.276 --> 00:33:40.576 align:middle
in the constructor and this is the
service you should get from our container.

00:33:41.466 --> 00:33:44.916 align:middle
I'm very old fashioned so I'm
not using the class name yet.

00:33:45.436 --> 00:33:51.926 align:middle
And this can be done in other, in other
frameworks using different extensions.

00:33:52.536 --> 00:33:56.886 align:middle
And now that PSR containers are
standardized, there is an extension

00:33:57.426 --> 00:34:00.866 align:middle
that will just let you directly plug any
container in including the Symfony container.

00:34:01.836 --> 00:34:07.216 align:middle
But it's best to use the Symfony extension
for this still because it will do things

00:34:07.216 --> 00:34:09.876 align:middle
like rebooting the kernel in between steps.

00:34:12.866 --> 00:34:15.016 align:middle
So I need to write a service and the service.

00:34:15.016 --> 00:34:21.226 align:middle
This is, this is the service object inside it,
it's using the domain objects I created earlier.

00:34:21.856 --> 00:34:27.026 align:middle
So it's a way of defining a sort
of course API for my domain model

00:34:27.626 --> 00:34:29.606 align:middle
that the controller is going to use.

00:34:30.396 --> 00:34:34.306 align:middle
The line in the controller is
going to end up looking like this.

00:34:34.576 --> 00:34:37.946 align:middle
It's just going to call a method on a service
with some primitives, with some scalers.

00:34:38.516 --> 00:34:44.296 align:middle
At this point you kind of need
to get infrastructure involved.

00:34:44.366 --> 00:34:46.756 align:middle
You definitely need to think about persistence.

00:34:48.156 --> 00:34:50.266 align:middle
Using real infrastructure is super slow.

00:34:51.116 --> 00:34:52.586 align:middle
Using real database is slow.

00:34:52.816 --> 00:34:58.976 align:middle
So it's best to use fake implementations or
infrastructure, like an in memory database

00:34:59.906 --> 00:35:02.626 align:middle
that can lower your confidence
because you think I'm not testing

00:35:02.626 --> 00:35:06.476 align:middle
with a real infrastructure you can
use a thing called contract tests

00:35:06.476 --> 00:35:09.056 align:middle
to make sure your fake infrastructure
behaves the same way

00:35:09.056 --> 00:35:11.986 align:middle
as your real infrastructure
to kind of mitigate that.

00:35:13.696 --> 00:35:17.016 align:middle
So I run through my other steps when
only Alice enrolls in this course.

00:35:17.046 --> 00:35:21.566 align:middle
So when enroll Alice, the
course will not be viable.

00:35:21.566 --> 00:35:23.636 align:middle
I'm not looking at the domain object directly.

00:35:23.636 --> 00:35:26.606 align:middle
I'm calling a method on the
course enrollment service,

00:35:28.596 --> 00:35:31.026 align:middle
so they're kind of two different options.

00:35:31.026 --> 00:35:36.926 align:middle
I wouldn't recommend testing the same
scenario against the domain objects

00:35:36.996 --> 00:35:41.656 align:middle
and the service layer, but something I
often do is I will write my tests directly

00:35:41.656 --> 00:35:46.276 align:middle
against the domain objects and then I'll
switch and start testing against the service

00:35:46.276 --> 00:35:48.956 align:middle
that wraps those domain objects,
if that makes sense.

00:35:48.956 --> 00:35:53.386 align:middle
So I kind of deliberately tests at
different layers because I want to be able

00:35:53.876 --> 00:35:57.166 align:middle
to completely change my domain
model without the tests failing.

00:35:59.356 --> 00:36:04.916 align:middle
I want to decide, course isn't an entity anymore
and actually it's all about learners enrolling

00:36:04.916 --> 00:36:07.906 align:middle
in tracks and that doesn't need to
be visible at the service layer.

00:36:07.906 --> 00:36:10.696 align:middle
That doesn't need to involve any
changes at the service layer.

00:36:11.256 --> 00:36:18.826 align:middle
At some point you want to test the
user interface, but not too much.

00:36:19.076 --> 00:36:20.796 align:middle
Don't start by testing the user interface.

00:36:21.336 --> 00:36:26.696 align:middle
At the moment the best way of doing
this is the behat/minkextension.

00:36:27.406 --> 00:36:32.846 align:middle
Mink is a API for driving lots of different
browser automation tools using the same

00:36:32.846 --> 00:36:33.436 align:middle
common API.

00:36:33.436 --> 00:36:40.206 align:middle
We interact with the domain model via the UI
and this checks, once we've got service layer

00:36:40.206 --> 00:36:44.226 align:middle
that works, we're basically checking that the
controllers are calling the right services.

00:36:44.966 --> 00:36:48.056 align:middle
Think about it as just just
validating that the UI works.

00:36:48.566 --> 00:36:52.906 align:middle
Don't do this kind of stuff.

00:36:52.906 --> 00:36:58.886 align:middle
If you start with the UI layer, you'll
end up putting loads of UI crap in the,

00:36:58.886 --> 00:37:00.996 align:middle
in the Behat scenarios, in
the Gherkin scenarios.

00:37:00.996 --> 00:37:04.636 align:middle
It's not the end of the world, but
you're missing a lot of opportunities to,

00:37:04.886 --> 00:37:07.296 align:middle
you can't have this conversation early.

00:37:07.296 --> 00:37:10.546 align:middle
And it's very brittle, when you
change the UI these things just break.

00:37:15.526 --> 00:37:20.216 align:middle
So to test, using mink, I
enable the Mink extension.

00:37:20.466 --> 00:37:23.456 align:middle
I already had the Symfony extension,
I can tell it use the Symfony driver.

00:37:24.486 --> 00:37:29.066 align:middle
This is gonna automate as if
we're doing browser automation,

00:37:29.066 --> 00:37:30.586 align:middle
but it doesn't require a real web server.

00:37:30.616 --> 00:37:34.366 align:middle
It's just booting the kernel and sending
a request and checking the response.

00:37:35.256 --> 00:37:40.836 align:middle
You can also use it with PSR
there's a PSR 7 driver they made.

00:37:41.136 --> 00:37:45.846 align:middle
So it looks kind of the same.

00:37:45.846 --> 00:37:48.756 align:middle
Again BDD for Beginners was proposed with
the class size of two to three people,

00:37:48.986 --> 00:37:52.496 align:middle
I'm still going to inject a service
and I'm still gonna call that service,

00:37:53.266 --> 00:37:56.176 align:middle
but maybe this is the service that's
connected to the real database, the real,

00:37:56.296 --> 00:38:00.306 align:middle
real test database, the real
MySQL test database.

00:38:01.946 --> 00:38:05.386 align:middle
When only Alice enrolls in this course, then
I need to write some browser automation code.

00:38:05.596 --> 00:38:10.236 align:middle
So Behat checks Alice enrolling
on a course in a different way.

00:38:10.236 --> 00:38:12.906 align:middle
Instead of calling PHP methods,
it's going to open a page

00:38:12.906 --> 00:38:14.946 align:middle
and fill in a form and submit the form.

00:38:16.836 --> 00:38:24.246 align:middle
The course not being viable, instead of checking
a boolean on a, on an object, we go to the page

00:38:24.246 --> 00:38:27.366 align:middle
and we say, does this element,
this CSS element exist?

00:38:28.596 --> 00:38:31.046 align:middle
Now I don't need to do this
for all of the scenarios.

00:38:31.186 --> 00:38:36.386 align:middle
I'm kind of confident that if I've got
10 scenarios about different situations

00:38:36.386 --> 00:38:42.056 align:middle
with different combinations of people sign
up and then unregister then register again,

00:38:42.306 --> 00:38:45.916 align:middle
and I've checked all of that at the
service layer, I probably only need

00:38:45.916 --> 00:38:47.556 align:middle
to check a few of them through the UI.

00:38:47.756 --> 00:38:50.616 align:middle
Specifically the ones where the
UI would do something different.

00:38:51.476 --> 00:38:55.536 align:middle
So I need to check one case where
the not viable warning appears.

00:38:55.536 --> 00:39:00.576 align:middle
I need to check one case where the, this is
oversubscribed thing appears I don't need

00:39:00.576 --> 00:39:05.156 align:middle
to check all of the combinations of what
could happen because I've got confidence

00:39:05.156 --> 00:39:07.416 align:middle
that the system, the underlying system works.

00:39:07.736 --> 00:39:10.496 align:middle
I'm just checking that the UI is
plugged into the services correctly.

00:39:11.006 --> 00:39:15.986 align:middle
So this can all be tested
through Symfony directly.

00:39:16.066 --> 00:39:18.536 align:middle
It runs on your laptop, it doesn't
need any extra infrastructure.

00:39:19.876 --> 00:39:26.966 align:middle
Some people automate real browsers,
mostly when you've got loads of JavaScript

00:39:27.436 --> 00:39:31.786 align:middle
and you've written a site that doesn't work
without JavaScript and you have a frontend team

00:39:31.786 --> 00:39:34.926 align:middle
who aren't doing any testing
any automated testing.

00:39:35.056 --> 00:39:39.616 align:middle
So it's very slow to automate a real browser.

00:39:39.756 --> 00:39:43.636 align:middle
They crash and do weird stuff.

00:39:45.746 --> 00:39:49.966 align:middle
It's often better to use Cucumber.js
and do a sort of layered approach

00:39:49.966 --> 00:39:52.956 align:middle
like I've been describing in the JS application.

00:39:54.126 --> 00:39:57.206 align:middle
It's better to do that then try and drive the
entire system end-to-end with a real browser

00:39:57.246 --> 00:40:00.046 align:middle
because that's how you end up
with four hour test builds.

00:40:02.916 --> 00:40:08.406 align:middle
The best way I've got at the moment of
doing this is using the chrome driver.

00:40:09.626 --> 00:40:12.606 align:middle
You can pass some extra stuff
to tell it to run headless.

00:40:12.606 --> 00:40:21.116 align:middle
This is actually an experimental
extension by this person,

00:40:21.116 --> 00:40:24.436 align:middle
who I don't know, that seems to work fast.

00:40:24.436 --> 00:40:26.416 align:middle
It talks to chrome across the debug port,

00:40:26.416 --> 00:40:29.656 align:middle
it's faster than selenium for
me, but it's a bit flakier.

00:40:32.126 --> 00:40:37.146 align:middle
And we used to have a lot of systems like
PhantomJS that would pretend to be a browser.

00:40:37.146 --> 00:40:41.176 align:middle
But if you've got a recent Chrome, you've
got a good browser automation tool already.

00:40:41.756 --> 00:40:45.066 align:middle
You can run Chrome in headless
mode, you can open up a debug port

00:40:45.626 --> 00:40:47.006 align:middle
and Behat can talk to it directly.

00:40:47.006 --> 00:40:49.606 align:middle
You don't need to install
selenium if you don't want to.

00:40:49.916 --> 00:40:54.436 align:middle
Maybe into CI and stuff you can use
selenium, but this will work directly and it's

00:40:54.436 --> 00:40:59.036 align:middle
in the background and you don't really notice
it's running or you know, the docker world now

00:40:59.036 --> 00:41:03.946 align:middle
so you can just get a docker image that has
a headless Chrome in it and it boosts itself

00:41:03.946 --> 00:41:05.086 align:middle
and then you can kill it afterwards.

00:41:05.686 --> 00:41:10.746 align:middle
So browser automation is much
less painful than it used to be.

00:41:10.746 --> 00:41:17.416 align:middle
So start by, start by having conversations,
try driving the domain objects directly.

00:41:18.436 --> 00:41:21.246 align:middle
Refactor them into services when you
feel like the domain objects have got

00:41:21.376 --> 00:41:23.616 align:middle
to a good place and test with the service layer.

00:41:24.076 --> 00:41:26.296 align:middle
Then test a few scenarios through the UI.

00:41:26.856 --> 00:41:32.286 align:middle
If you can't avoid javascript
entirely, it's good advice for life.

00:41:34.526 --> 00:41:43.516 align:middle
So future: currently you can't autowire
services into your Behat contexts.

00:41:43.516 --> 00:41:47.346 align:middle
The API is there inside Behat for that to work.

00:41:47.426 --> 00:41:52.366 align:middle
We just need someone, some brave person
to make it work in the Symfony extension.

00:41:52.366 --> 00:41:58.386 align:middle
I don't think it's impossible, there's stuff
there in Behat for figuring out what to inject

00:41:58.386 --> 00:42:02.966 align:middle
for specific argument, someone needs to hook
that into autowiring in the Symfony container.

00:42:03.206 --> 00:42:04.856 align:middle
So if anyone wants to volunteer
afterwards talk to me.

00:42:04.856 --> 00:42:08.336 align:middle
Symfony Panther is awesome.

00:42:09.846 --> 00:42:12.406 align:middle
Behat uses a thing called Mink,
which is an API that's common to all

00:42:12.406 --> 00:42:14.316 align:middle
of these different browser testing tools.

00:42:14.316 --> 00:42:20.446 align:middle
But in Symfony land we already have a common
API now across browserkit, Goutte and panther.

00:42:20.446 --> 00:42:24.356 align:middle
It'd be really nice to have a way
of like a convenient way of using

00:42:24.356 --> 00:42:29.166 align:middle
that directly inside your Behat
contexts and use the web test API

00:42:29.166 --> 00:42:31.126 align:middle
that you've maybe already know
instead of having to learn Mink.

00:42:31.126 --> 00:42:38.336 align:middle
And there's a lot of convergence across cucumber
tools so it's possible that it's possible,

00:42:38.336 --> 00:42:41.396 align:middle
Behat will become more like the
other cucumber tools by sharing code.

00:42:41.866 --> 00:42:43.836 align:middle
There's a project to maybe switch a lot of it

00:42:43.836 --> 00:42:47.216 align:middle
over to a shared go run time
that we haven't signed up for.

00:42:47.216 --> 00:42:48.716 align:middle
But a lot of the other cucumbers are doing it.

00:42:48.716 --> 00:42:51.926 align:middle
So we might succumb to peer pressure.

00:42:52.286 --> 00:42:55.056 align:middle
Thanks for your attention.

00:42:55.056 --> 00:42:56.956 align:middle
I went slightly over but we started late.

00:42:56.956 --> 00:42:57.726 align:middle
So I think that's okay.

00:42:58.146 --> 00:42:59.076 align:middle
I'm Ciarran.

00:42:59.076 --> 00:43:01.756 align:middle
If you want to talk about any
more of this stuff just grab me.

00:43:01.846 --> 00:43:04.236 align:middle
I can come and help you do it at your company.

00:43:04.236 --> 00:43:08.586 align:middle
I look after another tool called
PHPSpec, which is unit testing.

00:43:09.596 --> 00:43:10.276 align:middle
Check that out.

00:43:10.686 --> 00:43:15.126 align:middle
There's two meetups I'm involved in look at
them and if you want to see a working example

00:43:15.126 --> 00:43:17.506 align:middle
of the code, I was showing in the slides.

00:43:18.036 --> 00:43:19.826 align:middle
That's the URL on GitHub.

00:43:20.246 --> 00:43:29.916 align:middle
Probably don't have time for questions, so
enjoy the break and come and talk to me.

00:43:29.916 --> 00:43:31.756 align:middle
Thanks.

