Welcome back. Here's a function
that is supposed to have a side effect on one of its inputs.
The function is called, update_counts,
and it takes a string of letters,
and it takes a dictionary as input.
It's going to do some stuff.
It isn't returning any value,
so it's going to return none.
But it's going to have a side effect.
Counts_d is going to be changed.
It's going to be mutated somewhere in here.
On line three, it's doing something,
on line five, it's assigning to counts_d.
So, if we want to check whether update_counts is working correctly,
we need a side effect test.
To do a side effect test,
you're going to set up some known initial value for an object.
You're going to run the function,
and then you're going to see if that object is updated correctly.
In our case we're going to create a dictionary,
on line nine it's got two keys a, and b.
We're going to call update_counts on line 10,
and then we're going to check on lines 12,
and 14, two different tests,
to make sure that the counts dictionary has been updated correctly.
Now, what is update_counts supposed to do?
Well, it's supposed to count all of the letters
that appear in whatever string is passed into it like, aaab.
In this case, we're passing in a string that has,
three a's and one b,
and we're supposed to add if there are three more a's,
then this a should become six,
and there's one more b, so the b should become three.
That's what you see is the test.
We check at the end,
this count square bracket a equal to six,
and this counts square bracket b equal to three.
Let's check whether the test is actually working.
Turns out is not working.
There are errors in there.
We'll come back, and we will fix that function,
as we go along here.
But before we do that,
let's think about other tests that we might want to have
besides just the single test that we have here,
where we have the original counts dictionary on line nine,
and then we call update_counts on line 10.
What other initial dictionary might we want to try to pass into update_counts,
and what other strings might we want to pass in?
I have a couple of ways for you to think about how to
decide which test to run for a side-effect tests like this.
The first is just to think about edge cases.
What if we were to start with an initial counts dictionary that was empty.
I'm first going to get rid of all of our markings here.
Another possibility might be that we start with an empty dictionary,
and we call update_counts,
and then we check something about what it should equal at the end.
Counts, square bracket a should now be three,
there weren't any a's in the dictionary.
We didn't have a count for a's.
We have three a's that we passed in,
so we should now have a total of three.
That's one possibility.
Another edge case would be passing in an empty string.
Maybe we have the same counts dictionary that we had up here.
Now we're going to pass in to the update_counts function an empty string.
Then we would want to do tests to make sure that the counts haven't changed.
Count square bracket b, was two,
it should still be two because there
weren't any characters in the string that we passed in.
Some other possibilities you can imagine,
maybe we can call update_counts,
and we pass in a dictionary that
has the same name as it does inside.
Then we would have some tests to make sure that counts_d has been updated appropriately.
We could pass in a character string that includes letters that are
not in the dictionary as we did already up here.
That's one way to think about it.
It's just sort of ask yourself what are weird edge cases?
Another way to think about it is to look at what will be in
your code for update_counts and think about exercising all the paths through that code.
We're going to have a conditional.
If c is in the counts dictionary,
that's checking, is this character c new?
So, we ought to have two tests,
one for the possibility that a letter is in the dictionary already and another,
where the letter is not in the dictionary.
Or we could include both in the same test;
a string that has the letter g in it,
as well as, a's and b's.
The other thing is in our update_counts there's
going to be some iteration where we're going to go through all of the letters.
Until we're going to have some for-loop.
Edge case, for iteration,
is when you iterate through something that's empty.
That's why it's a good idea to have some update counts where we pass in an empty string.
That's going to exercise a path through
this for loop where we just skip everything inside the for loop.
Now we have a bunch of tests.
Let's say after I call this update_counts,
I should have another check on,
test.testEqual(counts-d) square bracket
a to equal three.
If I run this we're going to find most of our tests have failed, one of them passed.
If we pass in a counts dictionary that's initially a has three and b has two,
and we update_counts with an empty string,
we're still good, counts to b, is still two.
It didn't get mistaken the updated.
But we failed most of our other tests.
Let's see what we would have to do,
to correct the code here.
Let's take a look at our first test.
We're passing in this dictionary a3 and b2,
that's going to be the second parameter,
the first parameter, is the string aaab.
Then we're expecting that a should be six,
but it's actually two.
It starts with a value of three and it ends with a two.
You can look in the code and you can see what's going wrong here.
Is that when we first encountered the letter a,
so now the variable c is down to the letter a,
we're setting the key a in the dictionary to have the value one.
We used to have three, but now it's getting set to one.
Sees in the counts dictionary,
and then it's getting incremented to two.
Each time we encounter an a,
we keep resetting its count to be one.
My problem is that I'm always setting counts_d square brackets c to equal one.
I really should only do that in those cases where it's not already in the dictionary.
This ought to be inside an else clause.
It should be conditionally executed.
Now I think we're going to pass the more other tests.
In fact, that's sufficient to make it past all of the tests.
So, that side effect tests for you.
You create a side effect test,
whenever the function is supposed to make changes to a mutable object.
You set up an initial value for a variable like I did on line 11,
then you run the function like I did on line 12,
and then you see if the object that the variables bound to has been updated correctly.
That's what happens on lines 14 and 16.
I'll see you next time.