Heads up! To view this whole video, sign in with your Courses account or enroll in your free 7-day trial. Sign In Enroll
Preview
Start a free Courses trial
to watch this video
In this video, Iβll share some of my expansions to the 'checkForShip' test suite.
Resources
Video review
- We might have to adjust our functions as we go
- Itβs ok to throw away code that was working, even if you spent time writing tests for it already; it's one of the biggest benefits of having unit tests
- Our unit tests will tell us exactly what breaks, and how, as we rebuild parts of our code
Related Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign upRelated Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign up
The fire function is one of the last
things the game engine actually needs.
0:00
Isn't it amazing how fast we can build
stuff that sounded hard before we started?
0:04
So here's how I wrote my test suite for
the fire function.
0:08
All right.
So first,
0:11
I'll set up my test suite at
the bottom of the shiptest.js file.
0:12
The test suite is named fire, so I'll pass
fire as the string followed by a function.
0:20
Then Iβll import the fire
function at the top.
0:35
So it's available to all my specs.
0:38
I'll skip running the initial test in this
case because i know it's just going to
0:56
break at first, but
it's a good habit for you to keep.
1:00
All right, so
now I need a spec to test fire's behavior.
1:04
The first thing that comes to mind for
this function is that it should record
1:07
damage on the correct ship,
if there's a hit.
1:11
So I'll create a new spec that says,
it should record damage.
1:13
On the given player ship.
1:20
At a given coordinate.
1:27
So now, I need to tell fire
which player I'm targeting and
1:40
which location i'm guessing.
1:43
So, it should accept a player
parameter and a coordinate parameter.
1:46
That means I need a player object for
this test.
1:50
So, I'll say var player.
1:53
And the player will need at
least one ship at one location.
2:00
So, I'll say locations.
2:08
0, 0.
2:13
And after the location,
I'll add a damage array.
2:17
So if I set up a simple player object and
call fire at a location
2:26
I know is occupied, so
let's say fire player at 0,0.
2:32
The players only ship should have a
matching coordinate and its damage record.
2:40
Basically the ship should take
damage at the given location.
2:45
So let's write an expectation for that.
2:49
So right below will say,
2:51
expect (player.ships[0].damage
2:55
[0]).to.deep.equal.
3:02
And then will add 00.
3:12
So, if we run the test now in the console,
we can see that the test breaks at first.
3:18
So now let's go ahead and set up
the fire function in ship_methods.js.
3:31
So right below the damageShip function,
I'll create a new function called fire.
3:36
And we'll pass the fire
function two parameters,
3:47
player and coordinates.
3:52
Then I'll go ahead and
export the fire function at the bottom
3:55
of our file by saying
module.exports.fire = fire.
4:00
So now if I go over to the console and
run npm test.
4:10
We can see that the test
gives me an assertion error.
4:17
It says, expected undefined
to deeply equal [ 0, 0 ].
4:20
Now, the fire function doesn't yet
do anything to the target ship.
4:25
But I know that in the end if
a ship exist on my opponent's board
4:30
at the location I guessed I want to
run damageShip on that particular ship
4:34
using the location I
guessed when calling fire.
4:39
So I'll start with check for
ship using my guess and
4:46
the given player since this
returns a true or false value.
4:50
So inside my function I'll save it to a
variable named ship to use it internally.
4:56
Then I'll pass player and
coordinates as the arguments.
5:03
So, I don't need to worry at all
whether check for ship will work here.
5:09
Because my test suite has already proven
that it does exactly what I expect.
5:13
And that's super awesome.
5:18
It takes a huge load off my brain.
5:19
It's kind of like knowing that
a j.query function will just work and
5:21
you don't need to second guess it.
5:25
So here, I'm calling the variable ship,
because that's what it represents.
5:27
Okay, so if my opponent has a ship where
it guessed, then I wanted to take damage,
5:32
so I know which coordinates to pass in,
but how do I know which ship to pass?
5:37
Now, I could run through all my opponents'
ships and look for the one I want.
5:43
But that's already what checkForShip does.
5:48
And I don't want to repeat
all that logic here.
5:51
So instead, let's just go
refactor the checkForShip method.
5:53
Remember when I warned you that
we might have to adjust our for
5:57
functions, as we go.
6:00
So it's okay to throw away
code that was working,
6:02
even if we spent time writing tests for
it already.
6:05
In fact, this is one of the biggest
benefits of having unit test, red,
6:08
green, refactor.
6:12
Even though our test for checkForShip are
passing, it turns out we need check for
6:13
ship to work slightly different now.
6:18
So, our unit tests will tell us exactly
what breaks and how as we rebuild things.
6:20
So this is an easy fix.
6:27
I'll just have the checkForShip
function return the actual ship.
6:28
And instead of simply returning
true when finding a ship.
6:33
So replace true with ship.
6:36
And I've checked for ship find something
then I wanna call damaged ship
6:40
on that ship at my guessed location.
6:44
So in my file function I'll say.
6:46
If ship, then damageShip and
6:50
pass the ship and the coordinates.
6:56
All right, so
let's see what the test reports.
7:04
In my console, I'll run npm test.
7:07
Well, this is interesting, it looks
like all my checkForShip tests are now
7:13
failing because I've dramatically
changed the way checkForShip works.
7:18
But it looks like my fire test passes,
so that's good.
7:23
So back inside ship_test.js scrolling
all the way up to my checkForShip suite.
7:32
I can quickly fix my test up.
7:39
Now, my first test Is fine.
7:41
Because it still returns false
when it's finding nothing.
7:43
But i'll change my next specs
expectation to.deep.equal.
7:47
Then I'll pass (player.ships[0]).
7:58
All right, let's go over to
the console and run the test again.
8:05
And I see that my test is green now for
that particular spec, so
8:16
great now I know this strategy works.
8:20
Now moving forward for all tests
to pass we'll need to make similar
8:23
deeper quality comparisons in
the checkForShips suite, so
8:28
we'll edit some of our other expectations
to expect an array instead of troop.
8:32
Now we can simply copy and
paste this deep.equal
8:37
expectation across the rest of
the checkForShip suite, change some of
8:40
the values to match the first member of an
array, and everything should work great.
8:44
All right so I'll copy this deep.equal
method, from this expectation.
8:54
Then scroll down to the next spec.
9:00
Then replace the first and
second expectation.
9:04
Will leave the values at 0.
9:11
Then scroll down to the next spec and
replace all of these as well.
9:13
So we'll change the first one from to
be true to deep.equalplayer.ships at 0.
9:20
We'll do the same for the next one.
9:26
And this one will change
the value to one and
9:31
will do the same for
the next one change that so one, and
9:36
finally we'll replace the fifth one and
change this value to two.
9:40
Finally, I'll scroll
down to my fire suite.
9:48
Then I'll create one more spec
here inside the fire suite
9:51
by copying the first spec and
pasting a new spec right below.
9:54
I'll change this new spec's
description to should not
10:01
record damage if there is
no ship at my coordinates.
10:06
So when I change the target here to [9,
9],
10:16
I would expect the damage
array to be empty.
10:21
So let's change the expectation to say,
to.be.empty.
10:26
Then remove the second 0 value
here after damage, so let's see,
10:32
does fire now correctly leave
the ship on damage if we guess wrong?
10:37
Well let's see.
10:41
I'll go over to the console and
run npn test.
10:43
And yep, the test already passed.
10:50
Now, I might also want to add some
reporting to the fire function so
10:55
that players know whether they hit or not.
10:59
Since this is just a game engine,
11:02
we'd probably have a separate
reporting function
11:04
that did fancy stuff with the DOM or
printed a useful message in the console.
11:07
For now, this looks really good.
11:12
We have almost all the major logic for
the game in place.
11:14
Did you use other
assertions in your tests?
11:17
Did you build your fire
function differently?
11:19
Share your solutions in the community and
compare them to what you see here.
11:22
In this stage, we've learned how
to set up our files from Mocha.
11:26
The main file structure of
a test suite in Mocha and
11:29
a lot of useful chai assertions
to make writing test easy.
11:32
We also did a lot of BDD to outline the
basic logic of a battleship game engine.
11:36
It can feel strange, but
with practice you'll find that it
11:42
really is super helpful to
outline your ideas first.
11:44
We were able to refactor things easily and
11:48
know exactly what changed
in our code base.
11:51
Manual testing can never give
us that level of confidence.
11:54
And the next stage we'll learn some great
features of Mocha for reducing the amount
11:58
of test code we write, while also
improving the quality of our test output.
12:01
You need to sign up for Treehouse in order to download course files.
Sign upYou need to sign up for Treehouse in order to set up Workspace
Sign up