1 00:00:00,370 --> 00:00:02,780 You've seen a lot of testing material. 2 00:00:02,780 --> 00:00:05,690 Let's wrap up with some talk about advanced testing features you 3 00:00:05,690 --> 00:00:07,330 might use in the future. 4 00:00:07,330 --> 00:00:10,800 A big part of writing effective test is making sure that your test focus 5 00:00:10,800 --> 00:00:13,000 on one clear behavior. 6 00:00:13,000 --> 00:00:16,830 If your tests have a lot of external dependencies, then it's hard to know 7 00:00:16,830 --> 00:00:20,530 whether they're failing because of the function you're meaning to test or 8 00:00:20,530 --> 00:00:23,290 if actually one of the dependencies is failing. 9 00:00:23,290 --> 00:00:27,270 That makes the test less powerful in debugging because you might have to check 10 00:00:27,270 --> 00:00:30,490 functions other than the ones named in your test spec, 11 00:00:30,490 --> 00:00:31,930 you may not be sure where to start. 12 00:00:33,180 --> 00:00:36,890 For our outlining, we've also seen that it's sometimes helpful to pretend that we 13 00:00:36,890 --> 00:00:40,100 know how certain functions work in order to get started. 14 00:00:40,100 --> 00:00:43,520 We can take this idea even further with mocks and stubs. 15 00:00:44,550 --> 00:00:48,960 Mocks and stubs are two special kind of fake helpers for our test suites. 16 00:00:48,960 --> 00:00:51,830 We've been using fake helpers all along with the fake 17 00:00:51,830 --> 00:00:54,400 objects we set up before each test. 18 00:00:54,400 --> 00:00:57,610 Mocks and stubs are fake functions that fill in the gaps for 19 00:00:57,610 --> 00:01:00,090 our test units dependencies. 20 00:01:00,090 --> 00:01:04,570 Now developers don't always agree about the difference between mocks and stubs. 21 00:01:04,570 --> 00:01:07,470 But I've posted some links in the teacher’s notes that you can read to get 22 00:01:07,470 --> 00:01:08,920 a sense of the distinction. 23 00:01:09,960 --> 00:01:13,210 In this video, I'll show you a stubbed function to get you started 24 00:01:13,210 --> 00:01:15,150 thinking about more complex testing. 25 00:01:16,230 --> 00:01:19,740 We still need a function that will let players take their turn. 26 00:01:19,740 --> 00:01:23,270 That function should ask the current player to guess a location, 27 00:01:23,270 --> 00:01:27,260 fire on that location and then check whether the game is over afterwards. 28 00:01:27,260 --> 00:01:31,640 If it is, then it should return something to stop the game because the game is over. 29 00:01:31,640 --> 00:01:32,470 And if it isn't, 30 00:01:32,470 --> 00:01:36,050 then it should return something that lets the next player take their turn. 31 00:01:36,050 --> 00:01:40,000 Notice again, how I don't really know yet all the details of this function. 32 00:01:40,000 --> 00:01:43,528 I'm just making educated guesses about it to describe its general behavior. 33 00:01:43,528 --> 00:01:49,540 So in game_test.js, inside the game instance function suite, 34 00:01:49,540 --> 00:01:52,680 I'll create a new test suite for that function. 35 00:01:52,680 --> 00:01:53,798 I'll call it takeTurn. 36 00:02:00,919 --> 00:02:05,258 So here at the top of the suite, let's import the takeTurn function that will 37 00:02:05,258 --> 00:02:08,078 eventually be written in the game instance file. 38 00:02:22,458 --> 00:02:27,638 For my first spec, I'll test that takeTurn returns false when the game ends. 39 00:02:27,638 --> 00:02:32,218 So we'll say, it should return false if the game ends. 40 00:02:45,678 --> 00:02:48,178 This function combines several behaviors. 41 00:02:48,178 --> 00:02:51,640 Guessing, firing and checking the game status. 42 00:02:51,640 --> 00:02:53,850 We've already tested fire but 43 00:02:53,850 --> 00:02:58,100 we haven't yet implemented any functions that take input from the player. 44 00:02:58,100 --> 00:03:01,030 That's because we don't know yet about how it will be played. 45 00:03:01,030 --> 00:03:02,230 Will it be in a browser? 46 00:03:02,230 --> 00:03:04,660 Will it require manually typed commands? 47 00:03:04,660 --> 00:03:06,060 Will it use a game controller? 48 00:03:06,060 --> 00:03:09,060 So, we've kept our game engine in the dark about these questions so 49 00:03:09,060 --> 00:03:12,110 that we can use it in a variety of environments. 50 00:03:12,110 --> 00:03:14,870 So using stubs will let us test the logic 51 00:03:14,870 --> 00:03:18,610 that depends on these decisions without having to actually make them yet. 52 00:03:18,610 --> 00:03:23,136 For example, the takeTurn function will probably call a guess function to decide 53 00:03:23,136 --> 00:03:24,258 what happens next. 54 00:03:24,258 --> 00:03:28,578 Since I haven't written these yet, I can introduce a variable called guess, 55 00:03:28,578 --> 00:03:33,770 at the top of my function just like I've been doing for player and ship objects. 56 00:03:33,770 --> 00:03:37,908 So next, I'll create a before each block right above the spec here. 57 00:03:48,568 --> 00:03:53,368 In this block I can set guess to be a pretend function that doesn't do 58 00:03:53,368 --> 00:03:55,070 real game logic. 59 00:03:55,070 --> 00:03:57,870 Now I call these pretend functions because they 60 00:03:57,870 --> 00:04:02,680 just return the values I would expect the real working functions to produce. 61 00:04:02,680 --> 00:04:05,250 Guess will gather a location 62 00:04:05,250 --> 00:04:08,210 from the current player that they want to fire a shot on. 63 00:04:08,210 --> 00:04:10,470 This could be from a click in the browser or 64 00:04:10,470 --> 00:04:12,830 typed in the command line or some other method. 65 00:04:12,830 --> 00:04:15,710 Maybe it will even be spoken into a microphone, who knows? 66 00:04:15,710 --> 00:04:18,557 So no matter how players interact with guess, 67 00:04:18,557 --> 00:04:21,698 it will somehow need to return a valid coordinate. 68 00:04:21,698 --> 00:04:26,678 So that means I need to set guess to be a function that returns a valid coordinate. 69 00:04:26,678 --> 00:04:31,798 So inside the before each block, we'll say, guess = function. 70 00:04:34,576 --> 00:04:38,836 And inside the function, will return the coordinate [0, 0]. 71 00:04:44,556 --> 00:04:47,756 So now no matter how I write guess in the future, 72 00:04:47,756 --> 00:04:52,720 this test ensures that takeTurn does what I expect with the return value. 73 00:04:53,900 --> 00:04:58,530 Finally, takeTurn needs to know which player is taking their turn. 74 00:04:58,530 --> 00:05:01,790 So I'll initialize a player variable at the top. 75 00:05:01,790 --> 00:05:04,928 Then pass in a player object in my beforeEach block. 76 00:05:10,648 --> 00:05:16,068 I'll set a ships array as a property on the object. 77 00:05:16,068 --> 00:05:20,108 Then I’ll add a locations and an empty damage array to ships. 78 00:05:28,788 --> 00:05:32,564 So now, inside the spec if I call takeTurn with a player and 79 00:05:32,564 --> 00:05:37,740 the player guesses the last ship location of their opponent, the game is over. 80 00:05:39,080 --> 00:05:42,450 So I'll call takeTurn and pass player and 81 00:05:42,450 --> 00:05:47,760 guess as arguments and save it to a variable named actual. 82 00:05:50,980 --> 00:05:54,760 And again if the player guesses the last ship location of their opponent, 83 00:05:54,760 --> 00:05:55,700 the game is over. 84 00:05:55,700 --> 00:05:59,260 So in this case, takeTurn should return false. 85 00:05:59,260 --> 00:06:03,140 So we'll say expect actual to be false. 86 00:06:07,250 --> 00:06:10,290 So now, even though I have no working guess function, 87 00:06:10,290 --> 00:06:14,500 I've set up the spec to pretend that those parts of my code already work. 88 00:06:14,500 --> 00:06:17,368 That's the only important information this test needs. 89 00:06:17,368 --> 00:06:19,528 If I bring up my console and run my test. 90 00:06:25,169 --> 00:06:28,408 My test fails, it says, takeTurn is not a function. 91 00:06:32,158 --> 00:06:37,536 So now I’ll jump over to game_instance.js and write the takeTurn function here. 92 00:06:40,023 --> 00:06:45,981 So right below checkGameStatus, we'll say, function takeTurn. 93 00:06:49,021 --> 00:06:53,766 The takeTurn function will take a guess function call back and 94 00:06:53,766 --> 00:06:56,239 it will use this to save a guess. 95 00:06:57,300 --> 00:07:00,778 So we'll save a guessFunction in a variable named coordinates. 96 00:07:06,678 --> 00:07:10,887 The function will also take an opposing player call back to fire on the opposing 97 00:07:10,887 --> 00:07:12,558 player at those coordinates. 98 00:07:12,558 --> 00:07:14,858 So we'll also pass opposingPlayer. 99 00:07:18,138 --> 00:07:21,818 Then in the function will call fire and 100 00:07:21,818 --> 00:07:27,458 will pass opposingPlayer and coordinates as arguments. 101 00:07:27,458 --> 00:07:33,098 So now up top will need to import the fire function from ship_methods.js. 102 00:07:46,149 --> 00:07:49,063 So next to check whether the game is over, 103 00:07:49,063 --> 00:07:53,828 we'll declare a gameOver variable which calls checkGameStatus. 104 00:07:56,448 --> 00:08:00,506 And in the end the function returns the resulting status of gameOver so 105 00:08:00,506 --> 00:08:04,780 that we know whether to let the opposing player take their turn. 106 00:08:04,780 --> 00:08:08,392 So we'll say, return gameOver. 107 00:08:08,392 --> 00:08:12,754 And finally we'll export the takeTurn 108 00:08:12,754 --> 00:08:18,040 function here at the bottom of the file by typing 109 00:08:18,040 --> 00:08:22,948 module.exports.takeTurn = takeTurn. 110 00:08:22,948 --> 00:08:27,907 All right, so let's save our file, bring up the console, and run our tests. 111 00:08:33,066 --> 00:08:37,530 So great, even though guess has not been written, my test passes. 112 00:08:38,720 --> 00:08:44,440 The test spec used my stub version of the guess function instead. 113 00:08:44,440 --> 00:08:48,110 So it got all the values it needed just for testing my logic. 114 00:08:48,110 --> 00:08:51,800 So now I know that the logical structure of takeTurn is correct. 115 00:08:51,800 --> 00:08:54,380 So I can move on to writing something else. 116 00:08:54,380 --> 00:08:57,880 Another benefit of this stubbing is that even while I'm working on 117 00:08:57,880 --> 00:09:02,690 the checkGameStatus and guess functions, tinkering with them to do this or 118 00:09:02,690 --> 00:09:06,435 that my take turnTest will keep passing. 119 00:09:06,435 --> 00:09:10,110 takeTurn gets the value, I ultimately expect those functions to return 120 00:09:10,110 --> 00:09:11,860 no matter how those functions actually work. 121 00:09:13,010 --> 00:09:17,060 There are whole libraries dedicated to making stubs easy to write, 122 00:09:17,060 --> 00:09:19,085 like Signon.JS. 123 00:09:19,085 --> 00:09:24,670 Signon lets you set up pretend servers, HTTP requests, databases, and more. 124 00:09:24,670 --> 00:09:26,570 So if you wanna learn more about mocks and 125 00:09:26,570 --> 00:09:30,130 stubs, you can check out Signon's home page to see many more examples.