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