Check out a free preview of the full Testing Fundamentals course
The "Mocks" Lesson is part of the full, Testing Fundamentals course featured in this preview video. Here's what you'd learn in this lesson:
Steve explains mocks replace the actual implementation of a function and configure how it behaves in different test cases. Like spies, mocks keep track of how many times a function was called and with what arguments. Mocks combine the benefits of both stubs and spies, making them useful in more complex testing scenarios.
Transcript from the "Mocks" Lesson
[00:00:00]
>> Steve Kinney: I'll show you another one now, because we have the context. And I'll show you a few in here, and then we'll kind of look at the more practical examples, but let's play around a little bit more. So that's a spy, at any given point, you'll see why I don't care till I spend too much time on the different terms.
[00:00:23]
So we could also say, let's comment that out for a second. We can say,
>> Steve Kinney: Cool, so, this is a mock function, which is effectively just a effectively the same thing we wrapped around this. But in this case, it's gonna wrap an anonymous function, all right? So here, we can almost do the same thing, where we'd say,
>> Steve Kinney: What you're angry about?
[00:01:04]
Yeah, you're not called logs by anymore, are you? So this does the same thing. This creates just a bogus little function that you can call with whatever. And so remember how we talked about passing stuff in, right? Let's say you wanted to be able to pass a thing in, like, a function that you want called, so on and so forth, right?
[00:01:24]
This gives you a function that you can pass in, right? But it also allows you to then go look to see who called it, and how many times it got called. I'm gonna pass this function in, cause, yeah, this thing takes a call back, or whatever. I'm gonna pass this in and then I wanna see what happened to it when I sent it into, almost like a scientist.
[00:01:47]
I'm gonna take this little scientific like thing, I'm gonna toss it into this function and then I'm gonna look at it, who called you with what, right? And so, for instance, and we have these in some of the examples that I'll play with a little bit. You might have, let's say you had a reaction component that took a prop called on_submit, right?
[00:02:09]
Seems reasonable, or on click. You could take one of these mock functions, you toss it in there, and then you can test like, did you get called with the right form stuff, right? Did you get called the right number of times, right? You did? Great, it's a way to send a little scientific thing in there as well.
[00:02:29]
That is probably the best use case for one of these. Let's talk about one more. This is the one that gets people in trouble. You ready?
>> Steve Kinney: This is where we combine the two. So let's actually say, we're gonna call this one random spy. In this case, we're going to spy on math.
[00:03:00]
>> Steve Kinney: Is it a math.ran ot math.random? I was writing Python yesterday. Okay, math.random. No one's correcting me, so we're gonna assume that's true. Everyone's like, it's the afternoon. It's post lunch, I don't remember. I don't remember what the math that I'm if only one could do this and find out.
[00:03:17]
There we go. You know when you write 2 or 3 programming languages sometimes. All right, math.random. Fine, whatever, but then we can also do.
>> Steve Kinney: Now, we have gone into the JavaScript standard library. We have found the math function, right? Our math object, we found its random method.
[00:03:50]
We have hugged it and we said, when everyone, anyone calls you, do this instead, right? And so, that's a terrible choice, because math.random gives you a value of between 0 and 1. Let's do that instead. [LAUGH] That's a better option, because who knows what happens to our code.
[00:04:08]
Again, this is why mocks can be dangerous, because all of a sudden you're talking and you're typing, and you fundamentally change the way a function works. And then you're like, my tests are great, in no way tied to reality, but they're great. And so now, no matter what, right?
[00:04:23]
So in this case, we'll go take our random spy.
>> Steve Kinney: And we'll just do this instead. We'll say,
>> Steve Kinney: Result is math.random, right? And now we can expect result to be 5. Don't yeah, that's not how this works, 0.5.
>> Steve Kinney: I can run this test as many times as I want, because I've rid the world of randomness, right?
[00:05:04]
No matter what, Math.random is gonna return 0.5, right? Seems great. And honestly, Math.random is not the worst thing, that is on the level of things that are going to get you in trouble as long as you don't make it 10 or something like that, right? Is going to just hold that in place, which means we could theoretically go back over to those tests that we had earlier in the characters.
[00:05:38]
And what we could choose to do is, we can go into this character's test and remember how we just passed in this function that made it 15 all the time. We'll get rid of that for a second. And we're just gonna say,
>> Steve Kinney: Spy on Math.random, we gotta pull that in.
[00:06:13]
>> Steve Kinney: Important note, if you were using jest, it's now called VI. It's called Jest. [LAUGH] That's the difference between everything I'm doing in Jest and everything I'm doing in V test. Math, that's V random.
>> Steve Kinney: So in case somebody,
>> Steve Kinney: Not Implementation, if somebody gives you a quiz like, who cares about the rest of it?
[00:06:49]
Spying is just letting the initial thing happen. Mocking is replacing with your own behavior, okay? That's not going to get you past anyone who would like to be condescending about testing, but it will be fine for normal people. Mocking limitation.
>> Steve Kinney: 0.5, and so now the randomness here will always be the same.
[00:07:18]
In fact, I don't know how the dice rolling works and we're just gonna run it and see. We'll see there, and deal with it from there.
>> Steve Kinney: That turns out to be 12 with the value I handed in. So, now these could be 12, and I could roll that dice 1,000,000 times and it doesn't matter.
[00:07:43]
Because instead of calling Math.random, Math.random will always be 0.5, will always get consistent values, right? And that is one use case for doing this. And an important question to ask yourself, did we get a lot of value versus just having the expect any number? I don't know, right?
[00:08:13]
But the nice part about having this mock is you could theoretically be like, okay, like, how many times did random get called? Was it the right number? with what arguments did it get called? In this case, none, because Math.random doesn't take any arguments, right? But like in other cases, you do get the nice part of the introspection there as well, or we could have passed in a function that we could have done that same stuff with.
[00:08:35]
But it does give you the ability for stuff that you can't control, let's say, for instance, you had something. It was another use case where you might choose to control randomness is, all right, we're doing things just to give us a random word and create a game of hangman, right?
[00:08:51]
Well, then you could at least, instead of having a shuffled word, you can say always return this word or something along those lines. Especially when code you don't control, I will argue is dependency injection better, we could pass in something that generates a random number, and that is math.random by default, we can pass in a function.
[00:09:11]
You would get the same effect. You don't owe one that assumes, you have refactored the code or wrote it yourself. And that is a theme of this, course, is if you can pass in those external things, do that, right? Because remember with this one we made, just on a random thing we made a roll dice as a random thing as well.
[00:09:32]
What we could do is we could say, okay, Math.random still exists, right? So we talk Took away that mock ,so randomness is back, which means we gotta skip that first test [LAUGH] just for a second. But what's cool about when we mock out external things, the risk that somebody brought up early in this course of like, how divorced from reality are you is real, right?
[00:10:05]
But we can also pass in a Mock as that little scientific explorer that we saw before and see some really interesting things with it, right? So for instance, when we use it with dependency injection, and this is about how we structure our code, if you pass these things in, it's super interesting.
[00:10:21]
So it should roll the dice, or what is it? Four dice, 4,6-sided die. 4, 6,
>> Steve Kinney: Wow, there we go. It turns out I don't stand and type like this all day very often. So, here we've got that character. This is where I hate before each, I wanna do something different this time
>> Steve Kinney: Another Check.
[00:11:08]
>> Steve Kinney: Do you know what that does? It only runs that test. Do you know what you don't want to accidentally commit? Only, because you're like, ship it, right? But for our purposes right now.
>> Steve Kinney: So,
>> Steve Kinney: We have the new character.
>> Steve Kinney: We have the default level and I think we also then put in the ability, that last function is that roll dice function, right?
[00:11:43]
So what I would do here is,
>> Steve Kinney: And here I can pass it in this.
>> Steve Kinney: What's she mad about?
>> Steve Kinney: So now, this is going to be a replacement for that roll dice function that we can pass in. It's always gonna give us 15, right?
>> Steve Kinney: So now, we could theoretically say that, the characters got a strength of 15, right?
[00:12:32]
We can expect that, but that's not particularly interesting to us. Well, let's do that first.
>> Steve Kinney: Cool, but now I passed in that function, but like, hey, character, did you call roll dice with arguments of 4 and 6, right? How would I tell that otherwise? I can't really, because it's happening internal, I can say,
>> Steve Kinney: Verify that this function that I pass in there was called the way I think it was called, right?
[00:13:19]
More practically, we'll see this in a second. If you had a reactive one that took like an on Click, or on Submit, or on whatever, you could pass in that function and make sure it was called with the things you think it should be called with, right? And it gives you a way to use the pendency injection and pass it in, and then look at this function that I shot in there, was it called the way I thought it was, right?
[00:13:40]
And just to make this a little clearer.
>> Steve Kinney: That is my Mock function being called with 4 and 6. And I can even see, were you called six times?
>> Steve Kinney: I think it's 6 times, right? Yeah, all right and so like hey, you were called 6 times once for strength, intelligence, dexterity, constitution, wisdom intelligence Charisma.
[00:14:11]
Charisma, I don't know how I got to seven on my hands, despite that, that's impressive. And that it was called with 4 and 6, so on and so forth. Because under the hood, the console logging is going to suck a little bit, but let's see. Let's see if we can, moment of introspection in here.
[00:14:32]
These are all the things that adds to it, but you can say, rolldice.mock. And then you can see every call that was made to roll dice was recorded, right? And the arguments it was recorded with. All the results every time it was called were recorded, right? And so just using that like just.fn or vi.fn, right?
[00:14:58]
Gives you a function where you can see how many times was this function called? What was it called with? What did it return? Right, so you can see, it's called with 4 and 6 a bunch of times right, as we as we saw. We get to know what the code that consumed that function did with it, which is kind of super cool.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops