
continuing our journey on unit testing
in JavaScript in the last episode that
you can find in the episode description
we explored the why behind unit testing
and the why is to keep the complexity of
our code from overwhelming us today
though we are going to focus a little
bit more on what unit testing is and how
it helps with managing complexity
I am empty J’s and you are watching fun
function
[Music]
last week we wrote some code order total
the function order total order total was
a function that took a piece of data an
order and grabbed all the items in the
order and summarized them for us in an
in an order total today we’re going to
write that same function but we are
instead going to do it with a test first
approach I also want to state for the
record that today I am enormously tired
it’s just one of those days where the
caffeine doesn’t work let’s do some
coding and see if we can get some
energies today all right here on first
here on line one we call order total
with an order any recognize this sample
data from the last last episode and here
we check if the the the order total
returned from orders all isn’t 808 we
throw an error check fail by happy part
here I mean they’re basically the case
the standard case where everything goes
well there’s no weird edge cases or
anything it’s just the main main thing
that the function is supposed to do
alright so there’s no actual code here
or total here it does not exist yet we
wrote the test first can i us be the
devil’s advocate and ask why we are
doing it this way why are we writing the
test first instead of writing the code
first and then adding a test later
well the biggest benefit for with test
first for me is that it helps ensure
that I actually write the
tests at all I find that if I start
adding tests after I’ve written the code
when I try to do that I tend to slack on
that and the reason why I slack on that
is that it’s just harder to write tests
afterwards than before and the reason
why it’s harder is that it’s hard to
figure out what tests what tests right
okay can you can give an example okay
maybe can you perhaps can give an
example of that okay let’s have a look
at the code from the last episode how
how do I increase the font size zooming
zoom fantastic okay so these the this is
only eight lines of code but even just
at eight lines we already have multiple
use cases in the code and now since we
didn’t add the tests while we were
writing them I have to have two now
after the fact analyze the code and like
archaeology those out okay but is that
really all that hard no it’s not it’s
not rocket surgery by any means but it
is busy work that we can avoid adding
tests after the fact to me is like
adding an extra unnecessary archaeology
step where we try to extract things from
our own code if I try to make an analogy
and it’s an analogy so it’s not perfect
but it feels a little bit like if let’s
say that we were a chef and we we were
inventing a new recipe we were just
playing around and adding things to to
the soup and eventually like the soup
turned out really well and when we when
it then it’s time to write the recipe
down so that non cooks could do it and
as we didn’t really keep tabs on what
ingredients we put into the soup we now
have to like
hmmm look in the soup and like
after-the-fact try to figure out which
ingredients we put in there like poke
around in it
and that would sort of work we might
miss an ingredient there and might take
a little bit more time but it would work
but to me it seems like it would have
been more sensible to make notes of what
we added to the soup as we did it that
to me seems more effective and reliable
alright fair enough
let’s go back to the original code okay
we are doing test first today which
means that we only write code when there
exists a test that requires that code to
exist mmm I think I’m lisping a bit
today so in this case here we see that
order total does not exist that’s a very
obvious problem one part about unit
testing is that you constantly try to
put yourself in these situations where
the next step becomes obvious all right
function order total alright now it
fails for another reason
that’s good progress again unit testing
is about making these small very
incremental steps of progress towards a
goal we create this very nice feedback
loop for our work it’s almost a little
bit like like a game where you like you
when you hop on an enemy like that gives
you a satisfying group when you like the
Goomba goes away hey dice
and now like getting to a new level in a
video game we have a new challenge which
is that this check here this fails the
happy path a check fails because this is
not one eight oh eight no because this
is an empty function is returning
undefined so again let’s remember that
when we are doing tests first
we try to always only write code that is
required by a test to pass so
first impulse here might be to start
writing writing and reduce like order
items reduce but that’s not actually
what the tests requires if we are being
really strict about the rule of only
writing code that tests require we could
do return rate and test succeeds
what the what is this this
feels so unintuitive to me yes
this is if you do test first by the book
and really take it to its logical
conclusion this is what you what you end
up with like this is a very common
situation weird you are weird all right
so you really need to explain this to me
what okay we have the test passing now
but the code is obviously wrong how do
we how do we proceed from here all right
so there are three different approaches
that you can take when you are writing a
test first you can use obvious
implementation fake it till you make it
or triangulation and these techniques
they go from Orthodox to more chill
let’s talk about triangulation first
because that is the most conservative
way of doing test-driven development
okay triangulation what does that mean
exactly is that it is triangulation that
thing you do with points on a map and
you figure out where something is based
on three points yeah exactly that’s
where the name comes from and it’s kind
of similar in in unit testing because
often you find yourself in this
situation where one test is not quite
enough to drive the implementation
so let’s actually write another test I’m
just gonna copy paste this and I’m going
to do like drag on caller and I’m gonna
set that price to 20
we’re gonna do dragon shoe toy and I’m
gonna set that price to 4G perhaps and
I’m going to name this case happy path –
example1 example2 and this is supposed
to be 60 I’m doing the math in my head
and now we have this second test here
that is failing which will cause us to
actually have to write some code so
are you getting this with the whole
red-green cycle going on in in test
driven in test first that you oh it’s
red and you get sad and then you write
some code and then you get screen and
you go happy again and then red and you
go sad and yeah they’re getting it also
I would like to State for the record
that this feels really weird
uh I think I get it though I can see
value where the triangulation yeah I I
think this feels safe it feels like it’s
because it feels like it’s hard to make
mistakes with this and it also has this
quality of making it obvious what to do
exactly get to green at all costs just
focus on what code you need to write in
order to make the test pass and then
look at the code and try to figure out
what it is that we need to add and then
add a test for that and then the loop
continues again red green red green red
green however I would like to stress
that triangulation is not the only way
of doing tests first we could also have
gone immediately for the obvious
implementation once we had the first
test and just written written this
reduce function out because it is it’s
still kind of obvious that that is what
we are going for we could also take in a
middle road which is fake it till you
make it and that is kind of yeah that’s
in between so what we would have done
there is that we would have we would
still have first gotten to green as fast
as possible by just writing the
hard-coded value in 808 but then we
would have immediately replaced it with
the with the actual implementation so
you kind of it’s it’s kind of in-between
all of these are absolutely tests first
techniques
but they are different different
different in their Orthodox Ness if you
are a beginner it might be good to stick
with triangulation for a little while
because it’s the the simplest one it’s
the one that is most pure to test first
and it will be the technique that most
gives you a feel for test tests first as
something to integrate in your workflow
and then once you get the hang of it you
can start like dumping into these more
relaxed approaches sometimes okay now
that the initial weirdness feel has died
down I think a kind of like
triangulation though emotionally
conceptually I can see it being a bit
slow to work with well a bit slower a
bit more calmly paced but it does have
this huge benefit of giving me an
obvious way forward all the time that
seems very calming to me I can see
myself jumping between these actually
but falling back to triangulation on
days where I have more complicated
problems or perhaps some days where I’m
you know feeling a little bit lazy or
yes just having a down day and I have a
hard time thinking then triangulation
could kind of keep me from doing these
long thought jumps in my head and just
keep me focused on the red green red
green red green loop alright let’s let’s
add another test let’s let’s add our
quantity support
[Music]
all right so this test that we just
wrote the quantity quantity test now
works because we added code for that
however these tests here they have
failed and this have failed as well we
just don’t see it because this flows the
error first but this this would also
fail because these things have no
quantity in them and our code now expect
this we have we made a breaking change
okay yeah I get why does this we have we
have changed the API of our code and we
have tests in place to verify that API
which means that we now have to change
all our tests I feel like this is giving
us extra work fixing these tests and
this feels like work that wouldn’t exist
if we didn’t have the unit testing place
ah it kind of saw the right but you’re
also kind of sort of wrong you need to
have a little bit of imagination in this
particular case this is mostly as extra
work but that is true only because we
don’t yet have any external code that is
making use of our order total our test
did break because we actually made a
change to the a breaking change to the
API of already total if order total had
been in like some library that was used
by thousands of users you couldn’t make
a change like this without doing like a
major version bump and announcing it to
all the users because they might have
code that relies on that the API follows
a certain contract and that is what unit
tests verify so if or the total had been
in use for a while before we added the
quantity support then this the unit test
breakage here would actually have
highlighted a very real problem you know
what let’s I was about
to change these these two code example
these two tests here and just add
quantity one to them but I think that we
should pretend that code in in the
system is consuming this and perhaps
even third party code in in other
libraries because it it’s not
unreasonable to think that something
like order total might be very useful
for many system and that you might want
to change this logic or its share this
logic sorry so let’s actually make sure
that both cases work so I’m gonna warm
up my quantity 0 there does that work I
think I have to I put that in parents oh
no no it can’t be Syrians to be 1 and
yeah this works now observing this code
it feels like we are baking in a bit
much in the happy path examples now here
it feels like these are not actually
testing the happy path now they are
testing the happy path and lack of lack
or quantity or the lack of quantity case
so what I’m actually gonna do is that
I’m going to create a dedicated happy
path case
now that we have this check for no
quantity specified we can safely extend
these happy path examples to be actually
so as you see here we we keep the tests
very small and focused on one thing only
so you see here that this test for
instance there’s a lot of things that
this test does not test it doesn’t test
it only has one item so it’s not
concerned with with many items and it
also tests only the only the quantity
case like having no quantity case like
the implied quantity case that is that
is only con this test is only concerned
with that the happy part test it tests
it happens to test a little bit more but
these tests or if I use the happy part
test mainly to get me going to get
started and a happy path it’s okay that
tests a little bit more than one thing
but overall unit testing it refers to
like for the total as a unit that we can
test in isolation that’s that’s one way
of interpreting the unit word in unit
testing but it’s also important that
each test is a unit that it doesn’t like
test
hagh tons of code in hoc tones of cases
in in one test that becomes really
really hard to deal with
once multiple things start breaking it’s
a much nicer to to have each
each unit tests be it’ll be a unit in
this episode I also focused a lot on the
benefit of habit that unit tests have on
or test-driven development or test first
has on dealing with complexity but I
want to make a segue here and also note
that unit test also works as a
communication channel a really good
communication channel to your future
selves or your colleague yeah because
these tests basically double as very
specific and very nice executable
documentation for your code normal
documentation with you know examples and
stuff that is also very nice but unit
has a very like a very good supplement
to normal documentation because they get
really into the nitty-gritty of how
exactly a function works okay so uh what
about you know test runners I’ve heard
about mocha and jest and Jasmine and
whatever like we have not used them here
we have just done these very like very
hand coded handcrafted checks yeah I
have actually avoided introducing a test
runner at this stage because I I want
you as a viewer to learn as few things
as possible at the same time if we
introduce a test runner you would have
to learn a test runner while also
learning the basic principles of test
first and unit testing and it just feels
like we can introduce things
sequentially but test runners is what we
are going to talk about in the next
episode which brings me to that you have
just watched an episode on function I
really ever
Oh 800 GMT if you are watching from the
future you can check out next week’s
salute otherwise subscribe here so that
you don’t miss it
if you are forgetful you can also turn
on notifications
I am MJ until next Monday morning thank you