1 00:00:00,000 --> 00:00:04,543 [MUSIC] 2 00:00:04,543 --> 00:00:07,945 Writing unit tests might seem like magic sometimes, but in the end, 3 00:00:07,945 --> 00:00:10,400 we're still just writing JavaScript. 4 00:00:10,400 --> 00:00:13,810 You'll want to follow the same best practices you use when writing 5 00:00:13,810 --> 00:00:15,510 any JavaScript program. 6 00:00:15,510 --> 00:00:17,335 We should keep our test dry and tidy. 7 00:00:17,335 --> 00:00:22,560 In this stage, we'll explore some handy ways to avoid repeating ourselves. 8 00:00:22,560 --> 00:00:25,460 We'll also expand our tests to build our confidence and 9 00:00:25,460 --> 00:00:26,610 the code we've written so far. 10 00:00:27,920 --> 00:00:32,060 So far, I've been writing the dependencies for every test within each spec. 11 00:00:32,060 --> 00:00:33,820 For example, in our check for 12 00:00:33,820 --> 00:00:37,770 ship test suite, I wrote a new player object for every test. 13 00:00:37,770 --> 00:00:43,990 So the first test has a player, and the second test has the same exact player. 14 00:00:43,990 --> 00:00:49,730 So we need this code to simulate a player object to test the checkForShip function. 15 00:00:49,730 --> 00:00:53,960 In other words, the checkForShip function doesn't work without a player object, so 16 00:00:53,960 --> 00:00:58,700 we need to fake or mock a player object in order to test the function. 17 00:00:58,700 --> 00:01:02,290 So as you can see duplicating this code in our test file 18 00:01:02,290 --> 00:01:08,000 goes against the programming best practice of don't repeat yourself or dry. 19 00:01:08,000 --> 00:01:10,680 Fortunately Mocha, like all testing frameworks, 20 00:01:10,680 --> 00:01:15,450 comes with a few useful functions o help us set up conditions for tests, 21 00:01:15,450 --> 00:01:20,230 like creating test objects and simulating the conditions inside our app. 22 00:01:20,230 --> 00:01:22,530 This is called the Setup Phase, 23 00:01:22,530 --> 00:01:26,020 the part of our tests where we set up conditions for testing. 24 00:01:26,020 --> 00:01:30,030 In fact, Mocha splits the setup process into two blocks. 25 00:01:30,030 --> 00:01:33,580 The stuff we set up before the entire series of tests, and 26 00:01:33,580 --> 00:01:36,970 the stuff we set up before each individual test. 27 00:01:36,970 --> 00:01:38,750 Let me show you an example. 28 00:01:38,750 --> 00:01:42,540 The checkForShip function doesn't alter any other code. 29 00:01:42,540 --> 00:01:46,640 It doesn't have side effects on our player object or ships. 30 00:01:46,640 --> 00:01:48,550 It doesn't make changes anywhere. 31 00:01:48,550 --> 00:01:52,360 It just does some calculations and then gives us a report back 32 00:01:52,360 --> 00:01:55,940 that says pulse if there's no ship at the given coordinates, or 33 00:01:55,940 --> 00:01:59,060 it tells us which ship it found if there is one. 34 00:01:59,060 --> 00:02:02,490 So because checkForShip won't change a player object in any way, 35 00:02:02,490 --> 00:02:07,180 it's safe to set up a single player object once with the information we need and 36 00:02:07,180 --> 00:02:09,900 then use that for all of the checkForShip tests. 37 00:02:11,120 --> 00:02:14,240 So the first thing I'll do is initialize a player variable 38 00:02:14,240 --> 00:02:15,710 at the top of the test suite. 39 00:02:15,710 --> 00:02:22,030 So right after I import the checkForShip function, I'll type Var player. 40 00:02:23,890 --> 00:02:26,910 Then right below it, I'll set up a before block. 41 00:02:30,380 --> 00:02:34,120 So before just needs one argument, 42 00:02:34,120 --> 00:02:39,130 a function that runs before any of our test specs, to set up any state they need. 43 00:02:42,670 --> 00:02:47,840 In this case, each test spec needs a player object with a ship's array. 44 00:02:47,840 --> 00:02:53,830 So I'll simply cut the player object out of this first test spec and 45 00:02:53,830 --> 00:02:55,690 paste it into my before block. 46 00:02:57,530 --> 00:03:02,530 So now the first spec will have access to the same player it did initially. 47 00:03:02,530 --> 00:03:05,570 And before anything else happens in my test suite, 48 00:03:05,570 --> 00:03:10,080 Mocha will make a player object for all of the specs below to use. 49 00:03:10,080 --> 00:03:11,370 Pretty cool. 50 00:03:11,370 --> 00:03:16,270 So now I can go ahead and delete the player object from my second spec too, 51 00:03:16,270 --> 00:03:19,300 because it will use the same player object, the first one you used. 52 00:03:22,310 --> 00:03:26,020 Now to repeat this for the other specs, we have to make sure we're keeping 53 00:03:26,020 --> 00:03:29,680 all the added complexity those tests need in this player object. 54 00:03:31,120 --> 00:03:35,910 So for instance, when I get to the third spec, I see that the player object up 55 00:03:35,910 --> 00:03:40,190 here in the before block is going to need a bit more complexity for 56 00:03:40,190 --> 00:03:45,450 a test suite to work, because I see that this ship needs a second location. 57 00:03:45,450 --> 00:03:48,550 And in fact, the next test spec needs a bunch of ships. 58 00:03:49,670 --> 00:03:54,600 So, what we'll do is take the most complex player object in this suite and 59 00:03:54,600 --> 00:03:57,950 use it up here, in our before block. 60 00:03:57,950 --> 00:04:01,340 So, the last spec, and we check for ship suite, 61 00:04:01,340 --> 00:04:05,280 represents the most complicated object we need for any of our specs. 62 00:04:06,310 --> 00:04:11,700 So, I'll cut the ships array used in this last spec, and 63 00:04:11,700 --> 00:04:15,830 replace the one up top by pasting it in to the before block. 64 00:04:19,520 --> 00:04:23,100 All right, so now all the tests in my checkForShip suite 65 00:04:23,100 --> 00:04:25,520 will use this player object. 66 00:04:25,520 --> 00:04:28,530 But we only need to write it in one place, and it will work for 67 00:04:28,530 --> 00:04:31,960 both my complex test and for all the simpler tests too. 68 00:04:33,030 --> 00:04:37,940 So now I can go ahead and delete any player object in my checkForShip specs. 69 00:04:46,140 --> 00:04:51,100 So now, since all of my test backs have access to the player object and 70 00:04:51,100 --> 00:04:56,270 the before block, if I run the test in the console. 71 00:04:58,530 --> 00:05:00,463 Great. All my tests still pass. 72 00:05:07,323 --> 00:05:10,020 All right, so let's clean up the fire spec now. 73 00:05:11,130 --> 00:05:14,440 The fire function is different than checkForShip. 74 00:05:14,440 --> 00:05:16,720 Fire is not a pure function. 75 00:05:16,720 --> 00:05:19,840 It has side effects in other parts of our code base. 76 00:05:19,840 --> 00:05:24,050 In this case, fire changes the damage array of the shipped object. 77 00:05:24,050 --> 00:05:27,285 It's given by calling damageShip. 78 00:05:28,370 --> 00:05:30,510 So if we ran it over and over, 79 00:05:30,510 --> 00:05:34,040 we would just keep pushing damage records onto the same ship. 80 00:05:34,040 --> 00:05:38,210 So that means that our test specs will be altering the application state 81 00:05:38,210 --> 00:05:41,260 from one to another, which will mess up our expectations and 82 00:05:41,260 --> 00:05:45,200 maybe make them fail, even when our function works. 83 00:05:45,200 --> 00:05:48,780 So instead of setting up a ship once in a before block, 84 00:05:48,780 --> 00:05:53,000 like we did earlier, we'll reset the ship for each spec. 85 00:05:53,000 --> 00:05:56,920 To do this, we can use a beforeEach block. 86 00:05:56,920 --> 00:06:02,120 So first I'll initialize a player variable at the top of the fire suite. 87 00:06:02,120 --> 00:06:06,240 So right after I import the fire function, I'll type var player. 88 00:06:07,755 --> 00:06:12,450 beforeEach works just like before, only it will run the function 89 00:06:12,450 --> 00:06:17,250 before each spec instead of just once at the start of the whole suite. 90 00:06:17,250 --> 00:06:22,165 So, right after the player variable, I'll set up a before each block. 91 00:06:22,165 --> 00:06:29,626 [SOUND] If I copy just the player object 92 00:06:29,626 --> 00:06:36,613 below Into the beforeEach block. 93 00:06:36,613 --> 00:06:38,855 So I'll go ahead and remove var. 94 00:06:39,880 --> 00:06:45,510 That means that the player object will be overwritten before each test. 95 00:06:45,510 --> 00:06:50,520 So no matter what changes happen inside of the first spec, it will all be erased and 96 00:06:50,520 --> 00:06:52,920 set back up new for the next spec right here. 97 00:06:54,730 --> 00:06:57,620 That makes our application state predictable between specs, 98 00:06:57,620 --> 00:07:00,060 even when the function we're testing has side effects. 99 00:07:03,110 --> 00:07:07,270 A nice bonus of using before and beforeEach blocks for 100 00:07:07,270 --> 00:07:11,540 setup is that our suites feel easier to read. 101 00:07:11,540 --> 00:07:16,650 We can see exactly how the test author thinks this function needs to work. 102 00:07:16,650 --> 00:07:19,280 It acts like a little bit of documentation, for 103 00:07:19,280 --> 00:07:20,980 how the function is intended to be used. 104 00:07:24,050 --> 00:07:29,190 So if I save my file and run the test again in the console. 105 00:07:33,190 --> 00:07:35,850 Nice, all my tests still pass. 106 00:07:35,850 --> 00:07:40,500 So in the next video, we'll cover the last phase of a test suite, tear down.