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
It’s sometimes helpful to pretend that we know how certain functions work in order to get started. We can take this idea even further with mocks and stubs. Mocks and stubs are special kinds of "fake" helpers for our test suites; they fill in the gaps for our test unit’s dependencies.
Resources
Video review
- It’s sometimes helpful to pretend that you know how certain functions work in order to get started -- you can take this idea even further with mocks and stubs
- Using stubs lets you test logic that depends on important decisions about your code, without having to actually make them yet
- A test spec can use a "stub" version of a function to get all the values it needs for testing your logic, no matter how the real function is actually implemented
You've seen a lot of testing material.
0:00
Let's wrap up with some talk about
advanced testing features you
0:02
might use in the future.
0:05
A big part of writing effective test
is making sure that your test focus
0:07
on one clear behavior.
0:10
If your tests have a lot of external
dependencies, then it's hard to know
0:13
whether they're failing because of
the function you're meaning to test or
0:16
if actually one of
the dependencies is failing.
0:20
That makes the test less powerful in
debugging because you might have to check
0:23
functions other than the ones
named in your test spec,
0:27
you may not be sure where to start.
0:30
For our outlining, we've also seen that
it's sometimes helpful to pretend that we
0:33
know how certain functions
work in order to get started.
0:36
We can take this idea even
further with mocks and stubs.
0:40
Mocks and stubs are two special kind
of fake helpers for our test suites.
0:44
We've been using fake helpers
all along with the fake
0:48
objects we set up before each test.
0:51
Mocks and stubs are fake functions
that fill in the gaps for
0:54
our test units dependencies.
0:57
Now developers don't always agree about
the difference between mocks and stubs.
1:00
But I've posted some links in the
teacher’s notes that you can read to get
1:04
a sense of the distinction.
1:07
In this video, I'll show you
a stubbed function to get you started
1:09
thinking about more complex testing.
1:13
We still need a function that
will let players take their turn.
1:16
That function should ask the current
player to guess a location,
1:19
fire on that location and then check
whether the game is over afterwards.
1:23
If it is, then it should return something
to stop the game because the game is over.
1:27
And if it isn't,
1:31
then it should return something that
lets the next player take their turn.
1:32
Notice again, how I don't really know yet
all the details of this function.
1:36
I'm just making educated guesses about
it to describe its general behavior.
1:40
So in game_test.js,
inside the game instance function suite,
1:43
I'll create a new test suite for
that function.
1:49
I'll call it takeTurn.
1:52
So here at the top of the suite, let's
import the takeTurn function that will
2:00
eventually be written in
the game instance file.
2:05
For my first spec, I'll test that takeTurn
returns false when the game ends.
2:22
So we'll say,
it should return false if the game ends.
2:27
This function combines several behaviors.
2:45
Guessing, firing and
checking the game status.
2:48
We've already tested fire but
2:51
we haven't yet implemented any functions
that take input from the player.
2:53
That's because we don't know yet
about how it will be played.
2:58
Will it be in a browser?
3:01
Will it require manually typed commands?
3:02
Will it use a game controller?
3:04
So, we've kept our game engine in
the dark about these questions so
3:06
that we can use it in
a variety of environments.
3:09
So using stubs will let us test the logic
3:12
that depends on these decisions without
having to actually make them yet.
3:14
For example, the takeTurn function will
probably call a guess function to decide
3:18
what happens next.
3:23
Since I haven't written these yet,
I can introduce a variable called guess,
3:24
at the top of my function just like I've
been doing for player and ship objects.
3:28
So next, I'll create a before each
block right above the spec here.
3:33
In this block I can set guess to be
a pretend function that doesn't do
3:48
real game logic.
3:53
Now I call these pretend
functions because they
3:55
just return the values I would expect
the real working functions to produce.
3:57
Guess will gather a location
4:02
from the current player that
they want to fire a shot on.
4:05
This could be from
a click in the browser or
4:08
typed in the command line or
some other method.
4:10
Maybe it will even be spoken
into a microphone, who knows?
4:12
So no matter how players
interact with guess,
4:15
it will somehow need to
return a valid coordinate.
4:18
So that means I need to set guess to be a
function that returns a valid coordinate.
4:21
So inside the before each block,
we'll say, guess = function.
4:26
And inside the function,
will return the coordinate [0, 0].
4:34
So now no matter how I
write guess in the future,
4:44
this test ensures that takeTurn does
what I expect with the return value.
4:47
Finally, takeTurn needs to know
which player is taking their turn.
4:53
So I'll initialize a player
variable at the top.
4:58
Then pass in a player object
in my beforeEach block.
5:01
I'll set a ships array as
a property on the object.
5:10
Then I’ll add a locations and
an empty damage array to ships.
5:16
So now, inside the spec if I
call takeTurn with a player and
5:28
the player guesses the last ship location
of their opponent, the game is over.
5:32
So I'll call takeTurn and pass player and
5:39
guess as arguments and
save it to a variable named actual.
5:42
And again if the player guesses the last
ship location of their opponent,
5:50
the game is over.
5:54
So in this case,
takeTurn should return false.
5:55
So we'll say expect actual to be false.
5:59
So now, even though I have
no working guess function,
6:07
I've set up the spec to pretend that
those parts of my code already work.
6:10
That's the only important
information this test needs.
6:14
If I bring up my console and run my test.
6:17
My test fails, it says,
takeTurn is not a function.
6:25
So now I’ll jump over to game_instance.js
and write the takeTurn function here.
6:32
So right below checkGameStatus,
we'll say, function takeTurn.
6:40
The takeTurn function will take
a guess function call back and
6:49
it will use this to save a guess.
6:53
So we'll save a guessFunction
in a variable named coordinates.
6:57
The function will also take an opposing
player call back to fire on the opposing
7:06
player at those coordinates.
7:10
So we'll also pass opposingPlayer.
7:12
Then in the function will call fire and
7:18
will pass opposingPlayer and
coordinates as arguments.
7:21
So now up top will need to import
the fire function from ship_methods.js.
7:27
So next to check whether the game is over,
7:46
we'll declare a gameOver variable
which calls checkGameStatus.
7:49
And in the end the function returns
the resulting status of gameOver so
7:56
that we know whether to let
the opposing player take their turn.
8:00
So we'll say, return gameOver.
8:04
And finally we'll export the takeTurn
8:08
function here at the bottom
of the file by typing
8:12
module.exports.takeTurn = takeTurn.
8:18
All right, so let's save our file,
bring up the console, and run our tests.
8:22
So great, even though guess has
not been written, my test passes.
8:33
The test spec used my stub version
of the guess function instead.
8:38
So it got all the values it
needed just for testing my logic.
8:44
So now I know that the logical
structure of takeTurn is correct.
8:48
So I can move on to
writing something else.
8:51
Another benefit of this stubbing
is that even while I'm working on
8:54
the checkGameStatus and guess functions,
tinkering with them to do this or
8:57
that my take turnTest will keep passing.
9:02
takeTurn gets the value, I ultimately
expect those functions to return
9:06
no matter how those
functions actually work.
9:10
There are whole libraries dedicated
to making stubs easy to write,
9:13
like Signon.JS.
9:17
Signon lets you set up pretend servers,
HTTP requests, databases, and more.
9:19
So if you wanna learn more about mocks and
9:24
stubs, you can check out Signon's
home page to see many more examples.
9:26
You need to sign up for Treehouse in order to download course files.
Sign up