1 00:00:07,910 --> 00:00:11,605 Welcome back. Here's a function 2 00:00:11,605 --> 00:00:14,985 that is supposed to have a side effect on one of its inputs. 3 00:00:14,985 --> 00:00:18,300 The function is called, update_counts, 4 00:00:18,300 --> 00:00:21,120 and it takes a string of letters, 5 00:00:21,120 --> 00:00:23,850 and it takes a dictionary as input. 6 00:00:23,850 --> 00:00:25,815 It's going to do some stuff. 7 00:00:25,815 --> 00:00:27,910 It isn't returning any value, 8 00:00:27,910 --> 00:00:30,135 so it's going to return none. 9 00:00:30,135 --> 00:00:32,025 But it's going to have a side effect. 10 00:00:32,025 --> 00:00:34,650 Counts_d is going to be changed. 11 00:00:34,650 --> 00:00:36,935 It's going to be mutated somewhere in here. 12 00:00:36,935 --> 00:00:40,010 On line three, it's doing something, 13 00:00:40,010 --> 00:00:42,950 on line five, it's assigning to counts_d. 14 00:00:42,950 --> 00:00:47,330 So, if we want to check whether update_counts is working correctly, 15 00:00:47,330 --> 00:00:56,670 we need a side effect test. 16 00:00:56,670 --> 00:00:58,410 To do a side effect test, 17 00:00:58,410 --> 00:01:03,125 you're going to set up some known initial value for an object. 18 00:01:03,125 --> 00:01:04,970 You're going to run the function, 19 00:01:04,970 --> 00:01:09,980 and then you're going to see if that object is updated correctly. 20 00:01:09,980 --> 00:01:12,755 In our case we're going to create a dictionary, 21 00:01:12,755 --> 00:01:16,595 on line nine it's got two keys a, and b. 22 00:01:16,595 --> 00:01:20,045 We're going to call update_counts on line 10, 23 00:01:20,045 --> 00:01:22,640 and then we're going to check on lines 12, 24 00:01:22,640 --> 00:01:24,545 and 14, two different tests, 25 00:01:24,545 --> 00:01:29,945 to make sure that the counts dictionary has been updated correctly. 26 00:01:29,945 --> 00:01:33,005 Now, what is update_counts supposed to do? 27 00:01:33,005 --> 00:01:36,335 Well, it's supposed to count all of the letters 28 00:01:36,335 --> 00:01:40,820 that appear in whatever string is passed into it like, aaab. 29 00:01:40,820 --> 00:01:44,090 In this case, we're passing in a string that has, 30 00:01:44,090 --> 00:01:46,055 three a's and one b, 31 00:01:46,055 --> 00:01:51,165 and we're supposed to add if there are three more a's, 32 00:01:51,165 --> 00:01:53,145 then this a should become six, 33 00:01:53,145 --> 00:01:56,625 and there's one more b, so the b should become three. 34 00:01:56,625 --> 00:01:58,695 That's what you see is the test. 35 00:01:58,695 --> 00:02:00,060 We check at the end, 36 00:02:00,060 --> 00:02:02,525 this count square bracket a equal to six, 37 00:02:02,525 --> 00:02:06,005 and this counts square bracket b equal to three. 38 00:02:06,005 --> 00:02:09,275 Let's check whether the test is actually working. 39 00:02:09,275 --> 00:02:12,170 Turns out is not working. 40 00:02:12,170 --> 00:02:13,735 There are errors in there. 41 00:02:13,735 --> 00:02:16,585 We'll come back, and we will fix that function, 42 00:02:16,585 --> 00:02:18,050 as we go along here. 43 00:02:18,050 --> 00:02:19,430 But before we do that, 44 00:02:19,430 --> 00:02:23,120 let's think about other tests that we might want to have 45 00:02:23,120 --> 00:02:27,170 besides just the single test that we have here, 46 00:02:27,170 --> 00:02:31,190 where we have the original counts dictionary on line nine, 47 00:02:31,190 --> 00:02:34,535 and then we call update_counts on line 10. 48 00:02:34,535 --> 00:02:40,670 What other initial dictionary might we want to try to pass into update_counts, 49 00:02:40,670 --> 00:02:43,565 and what other strings might we want to pass in? 50 00:02:43,565 --> 00:02:47,840 I have a couple of ways for you to think about how to 51 00:02:47,840 --> 00:02:52,025 decide which test to run for a side-effect tests like this. 52 00:02:52,025 --> 00:02:55,595 The first is just to think about edge cases. 53 00:02:55,595 --> 00:03:01,265 What if we were to start with an initial counts dictionary that was empty. 54 00:03:01,265 --> 00:03:06,540 I'm first going to get rid of all of our markings here. 55 00:03:07,640 --> 00:03:12,380 Another possibility might be that we start with an empty dictionary, 56 00:03:12,380 --> 00:03:15,000 and we call update_counts, 57 00:03:18,280 --> 00:03:24,460 and then we check something about what it should equal at the end. 58 00:03:30,590 --> 00:03:34,185 Counts, square bracket a should now be three, 59 00:03:34,185 --> 00:03:36,680 there weren't any a's in the dictionary. 60 00:03:36,680 --> 00:03:38,300 We didn't have a count for a's. 61 00:03:38,300 --> 00:03:39,990 We have three a's that we passed in, 62 00:03:39,990 --> 00:03:42,870 so we should now have a total of three. 63 00:03:44,360 --> 00:03:47,135 That's one possibility. 64 00:03:47,135 --> 00:03:53,070 Another edge case would be passing in an empty string. 65 00:03:53,620 --> 00:04:01,170 Maybe we have the same counts dictionary that we had up here. 66 00:04:05,230 --> 00:04:13,710 Now we're going to pass in to the update_counts function an empty string. 67 00:04:13,730 --> 00:04:20,270 Then we would want to do tests to make sure that the counts haven't changed. 68 00:04:25,010 --> 00:04:29,010 Count square bracket b, was two, 69 00:04:29,010 --> 00:04:31,060 it should still be two because there 70 00:04:31,060 --> 00:04:34,370 weren't any characters in the string that we passed in. 71 00:04:36,410 --> 00:04:39,625 Some other possibilities you can imagine, 72 00:04:39,625 --> 00:04:43,730 maybe we can call update_counts, 73 00:04:43,730 --> 00:04:50,040 and we pass in a dictionary that 74 00:04:50,040 --> 00:04:56,890 has the same name as it does inside. 75 00:05:01,910 --> 00:05:08,540 Then we would have some tests to make sure that counts_d has been updated appropriately. 76 00:05:08,540 --> 00:05:12,160 We could pass in a character string that includes letters that are 77 00:05:12,160 --> 00:05:16,230 not in the dictionary as we did already up here. 78 00:05:16,230 --> 00:05:18,080 That's one way to think about it. 79 00:05:18,080 --> 00:05:21,560 It's just sort of ask yourself what are weird edge cases? 80 00:05:21,560 --> 00:05:26,990 Another way to think about it is to look at what will be in 81 00:05:26,990 --> 00:05:33,450 your code for update_counts and think about exercising all the paths through that code. 82 00:05:33,670 --> 00:05:37,620 We're going to have a conditional. 83 00:05:38,890 --> 00:05:42,370 If c is in the counts dictionary, 84 00:05:42,370 --> 00:05:46,050 that's checking, is this character c new? 85 00:05:46,050 --> 00:05:47,620 So, we ought to have two tests, 86 00:05:47,620 --> 00:05:52,160 one for the possibility that a letter is in the dictionary already and another, 87 00:05:52,160 --> 00:05:54,565 where the letter is not in the dictionary. 88 00:05:54,565 --> 00:05:57,645 Or we could include both in the same test; 89 00:05:57,645 --> 00:05:59,985 a string that has the letter g in it, 90 00:05:59,985 --> 00:06:02,890 as well as, a's and b's. 91 00:06:03,260 --> 00:06:07,290 The other thing is in our update_counts there's 92 00:06:07,290 --> 00:06:11,235 going to be some iteration where we're going to go through all of the letters. 93 00:06:11,235 --> 00:06:14,640 Until we're going to have some for-loop. 94 00:06:14,640 --> 00:06:17,665 Edge case, for iteration, 95 00:06:17,665 --> 00:06:20,275 is when you iterate through something that's empty. 96 00:06:20,275 --> 00:06:25,340 That's why it's a good idea to have some update counts where we pass in an empty string. 97 00:06:25,340 --> 00:06:28,190 That's going to exercise a path through 98 00:06:28,190 --> 00:06:33,690 this for loop where we just skip everything inside the for loop. 99 00:06:33,920 --> 00:06:37,440 Now we have a bunch of tests. 100 00:06:37,440 --> 00:06:41,590 Let's say after I call this update_counts, 101 00:06:41,590 --> 00:06:44,750 I should have another check on, 102 00:06:44,750 --> 00:06:50,150 test.testEqual(counts-d) square bracket 103 00:06:50,150 --> 00:06:59,520 a to equal three. 104 00:07:02,090 --> 00:07:08,915 If I run this we're going to find most of our tests have failed, one of them passed. 105 00:07:08,915 --> 00:07:15,490 If we pass in a counts dictionary that's initially a has three and b has two, 106 00:07:15,490 --> 00:07:18,535 and we update_counts with an empty string, 107 00:07:18,535 --> 00:07:23,105 we're still good, counts to b, is still two. 108 00:07:23,105 --> 00:07:25,535 It didn't get mistaken the updated. 109 00:07:25,535 --> 00:07:27,760 But we failed most of our other tests. 110 00:07:27,760 --> 00:07:29,250 Let's see what we would have to do, 111 00:07:29,250 --> 00:07:31,720 to correct the code here. 112 00:07:32,870 --> 00:07:36,850 Let's take a look at our first test. 113 00:07:37,550 --> 00:07:42,165 We're passing in this dictionary a3 and b2, 114 00:07:42,165 --> 00:07:44,580 that's going to be the second parameter, 115 00:07:44,580 --> 00:07:47,315 the first parameter, is the string aaab. 116 00:07:47,315 --> 00:07:51,080 Then we're expecting that a should be six, 117 00:07:51,080 --> 00:07:53,935 but it's actually two. 118 00:07:53,935 --> 00:07:58,450 It starts with a value of three and it ends with a two. 119 00:07:58,610 --> 00:08:02,550 You can look in the code and you can see what's going wrong here. 120 00:08:02,550 --> 00:08:07,140 Is that when we first encountered the letter a, 121 00:08:07,570 --> 00:08:13,010 so now the variable c is down to the letter a, 122 00:08:13,010 --> 00:08:19,400 we're setting the key a in the dictionary to have the value one. 123 00:08:19,400 --> 00:08:22,300 We used to have three, but now it's getting set to one. 124 00:08:22,300 --> 00:08:24,525 Sees in the counts dictionary, 125 00:08:24,525 --> 00:08:27,275 and then it's getting incremented to two. 126 00:08:27,275 --> 00:08:29,390 Each time we encounter an a, 127 00:08:29,390 --> 00:08:33,065 we keep resetting its count to be one. 128 00:08:33,065 --> 00:08:40,290 My problem is that I'm always setting counts_d square brackets c to equal one. 129 00:08:40,290 --> 00:08:46,005 I really should only do that in those cases where it's not already in the dictionary. 130 00:08:46,005 --> 00:08:49,980 This ought to be inside an else clause. 131 00:08:57,380 --> 00:08:59,930 It should be conditionally executed. 132 00:08:59,930 --> 00:09:03,110 Now I think we're going to pass the more other tests. 133 00:09:03,110 --> 00:09:07,560 In fact, that's sufficient to make it past all of the tests. 134 00:09:08,050 --> 00:09:11,105 So, that side effect tests for you. 135 00:09:11,105 --> 00:09:12,890 You create a side effect test, 136 00:09:12,890 --> 00:09:16,865 whenever the function is supposed to make changes to a mutable object. 137 00:09:16,865 --> 00:09:21,920 You set up an initial value for a variable like I did on line 11, 138 00:09:21,920 --> 00:09:25,205 then you run the function like I did on line 12, 139 00:09:25,205 --> 00:09:30,065 and then you see if the object that the variables bound to has been updated correctly. 140 00:09:30,065 --> 00:09:33,775 That's what happens on lines 14 and 16. 141 00:09:33,775 --> 00:09:36,600 I'll see you next time.