Unit Testing (Vitest) Tutorial #12 - Creating Spies

Net Ninja · Beginner ·🛠️ AI Tools & Apps ·7mo ago

Key Takeaways

The video tutorial covers unit testing with Vitest, specifically creating spies to track function calls and test side effects. It demonstrates how to use Vitest's spy method to create spies, assert function calls, and access invocation call order.

Full Transcript

All right then, gang. In this lesson, we're going to talk about something which is in some ways similar to mocking functions, and that is spying on functions. So, when we spy a function, we're not replacing it with a fake one like we do when we mock a function. Instead, we're keeping the original exactly as it is, but we're just watching what happens when it's called. And just like with mocks, we can track how many times it's been called, what arguments it received, and what values it returned. But unlike mox, a spy lets the original function logic still run unless we choose to manually override it. So using a spy might be a good idea when we want to test maybe the side effects of a function call or to verify that it was triggered correctly at the right time without removing its behavior. In this lesson then we're going to spy a function and see how all of this works. Now to do that we'll be working with a brand new function that I've already created inside this setup game.js JS file in the source directory. And inside this file, we import two of the other functions we've already created throughout this series so far. The shuffle one, and the deal one. Now, this setup game function takes in three arguments. An array of cards, a hand size, and the number of players. Inside the function, we shuffle the cards first, and then we deal those shuffled cards using the deal function together with the hand size that we take in and the number of players. Then we create a new constant called players which will be an array of player objects. And to make those player objects we use the map method on the hands array. So inside the players array then each player object will have these three properties. An ID property which we're making using the index of the original hands and a hand property which will be an array of card objects dealt to them and then a final one called current turn which is a boolean. And that should be true for the first player where the index is equal to zero but initially false for every other player. And then finally we return the players array. So this function brings together some of the functions we already have to start a new game of cards. Right. And these are the two function calls right here that we're going to spy on. And now we're going to test this function inside a new test file which I've already prepped as well inside the test folder called setupgame.test.js. So then inside this file we already import four things from vest describe it expect and v which is what we used in the last lesson to mock functions. In this lesson we'll be using it to spine functions. I've also imported two functions we'll be needing inside the test. The create cards one to actually create an array of cards and the setup game one. Then we have a new test suite called setup game. And inside that, we've got some suits and values already created that we can pass into the create cards function to generate the cards. I've also created a couple of test cases ready for us down here, which we're going to work through. And in both of these, we're invoking this create cards function to generate the cards array for us, which we can then pass into the setup game function. And again, because we're bringing different parts of the application together in a single test here, we are technically wandering into the realms of integration testing, but we know that the create card function uh produces predictable results. So, it won't have any actual bearing on the tests unless we pass in invalid arguments. Anyway, this first test case says it calls shuffle before dealing cards. So that's what we want to test right now that the shuffle function gets called before the deal function inside the setup game function. To do that then we can make a new spy to spy on the shuffle function. But how do we do that? Well, let's start by making a new constant here which I'm going to call shuffle spy. And I'm going to set that equal to v which we imported and then use a method on that called spy on and invoke it. So this method lets us spy on a function from any given module. And to do that we need to pass in two arguments. The module itself and then the function name within that module. So then we need to import this module at the top of the file. So we can use it in the spy on method. And we can do that by saying import then an asterisk which means import the whole module and then we say as followed by whatever name we want to give this imported module. So we could call this shuffle module for example, but it can be called whatever you want. And then we'd use this name to refer to that imported module when we use it. Anyway, that comes from dot do/ to come out of this current folder then into the source folder and then the file name is shuffle. Okay, so now we've imported that module. We can go ahead now and use it in the spyon method. So let's come back down here and pass that shuffle module in as the first argument. So that now we're telling V test that we want to spy on something from within this module as a second argument. Then we need to pass in a string which should be the name of the function in that module that we want to spy on. So in our case that's the shuffle function. So let's add that in. Okay then. So now we're spying on this function using this shuffle spy and we can make assertions on that shuffle spy now to verify how many times it's been called and with what arguments and so forth. Before we do that though, we need to invoke the setup game function, don't we? Because within that the shuffle function gets invoked as well. So as arguments to the setup game call, we can pass in the cards, then five for the hand size and then we'll say three for the number of players. Okay, then so the first assertion is going to be a simple one. I just want to make sure this gets called one time this function, this shuffle one. So let's say expect and then pass in the shuffle spy and then we should add on a matcher which is to have been called times and then we'll pass in one. Let's save that and run the test over here just to make sure it passes which it does. Awesome. Okay, so the next one is to make sure that the shuffle function runs before the deal function here. All right, because we want to deal with shuffled cards. So what I'm going to do is say expect and I'm going to paste something in then I'll explain it. So we take the shuffle spy and we use a property on it called mock. And you might be thinking that's a little bit weird because we're not mocking this function. And that is correct. But this mock property is basically metadata. It's where V test stores all the tracking information about function calls regardless of whether it's a spy or a mock. And on that property we can access the invocation call order property which is an array of numbers. And those numbers represent the global call order of any tracked functions including spies. So we're saying get the number the global order of the first time this function was called. Right? And then we're going to tack on a matcher which is to be less than. And then we want to check the same thing for the deal spy because we want the global number of the first call of this function, the shuffle one, to be less than the deal one. So, we need a deal spy. And to do that, we're going to have to import the module. So, let's duplicate that and change this to deal module. And that's from the deal file. And then down here, I'm going to duplicate this. And we'll call this deal spy. And that comes from the deal module. And the function call uh the function is called deal. All right. So now we can say dealspy down here dot mock and then dot invocation call order and we want the first time that this was called. So this number right here should be less than this number if this was called first. This shuffle function. So let's save that and run this. And we can see that this passes right. Awesome. However, check this out. If I change the order of these things, I'm going to cut that and paste it down here. And I'll change this argument to cards because shuffle cards at this point hasn't been made. But now if we run this, it should fail. This should fail right here because the order of these have been changed. So now it's not less than this. So let's change it back to make sure it passes again. Like so. Save it. Run the tests. Yep. Awesome. All right then. So now let's do this second test case down here which says it calls deal with the correct arguments. So again, we have the cards right here using this function. And now I'm just going to paste in a few things. So we have a deal spy set up again using this spy on method and a shuffle spy. So we're spying on those two functions again. Then we have a call to this setup game function and we're passing the cards five for the hand size and three for the number of players. Now if we take a look at the function, we can see that the deal function should be called with that correct hand size and number of players. So the second two arguments here, but not with the cards, but with the shuffled cards right here. And we get that from this shuffle function. So we need to somehow access what is returned from this using the spy. And we can do that. We can get the shuffled cards right here by using the shuffle spy. Then we say domok again like we did up here. And then we can get the results from that call. And then we want the first set of results and we want to grab the value from that. All right. So now we say expect the deal spy to have been called with the shuffled cards and then five which is the same as up here and three. Okay. So let's save this and run the tests to see if they work. And yep they do. However, check this. If I was to just pass in the regular cards, save this and rerun the tests. Then now it's going to fail because this right here is incorrect. It's not called with the cards. it's called with the shuffled cards instead. So, let's save that. Run the test again. And now they pass. So then, my friends, that's how we create spies in Vest to spy on functions. They're a little bit like mock functions in that we can make assertions about the functions we spy on, much like we can with mocks. But whereas mock functions change the implementation of the functions, spies don't do that by default. So if you want to keep the original function implementation and you just want to watch what it does, then making a spy for that function would probably be a better option. Next up, we're going to have a quick lesson about something called setup and tearown.

Original Description

In this Unit Testing tutorial series, you'll learn how to setup Vitest in a project, and use it to write effective unit tests for your code. 🍿👇 Get the Testing Bundle (inc Testing Next/React) for just $7: https://netninja.dev/p/testing-bundle 🍿👇 Get early access to the course on NetNinja.dev: https://netninja.dev/p/unit-testing-with-vitest-crash-course 🔥👇 Get access to premium courses with Net Ninja Pro: https://netninja.dev/p/net-ninja-pro/#prosignup 🔗👇 Course files on GitHub: https://github.com/iamshaunjp/vitest-unit-testing-tutorial 🔗👇 Vitest Docs: https://vitest.dev/guide/
Watch on YouTube ↗ (saves to browser)
Sign in to unlock AI tutor explanation · ⚡30

Playlist

Uploads from Net Ninja · Net Ninja · 0 of 60

← Previous Next →
1 Regular Expressions (RegEx) Tutorial #14 - Matching a Username
Regular Expressions (RegEx) Tutorial #14 - Matching a Username
Net Ninja
2 Regular Expressions (RegEx) Tutorial #15 - Email RegEx Pattern
Regular Expressions (RegEx) Tutorial #15 - Email RegEx Pattern
Net Ninja
3 Regular Expressions (RegEx) Tutorial #16 - Finishing Touches
Regular Expressions (RegEx) Tutorial #16 - Finishing Touches
Net Ninja
4 GraphQL Tutorial #1 - Introduction to GraphQL
GraphQL Tutorial #1 - Introduction to GraphQL
Net Ninja
5 GraphQL Tutorial #2 - A Birdseye View of GraphQL
GraphQL Tutorial #2 - A Birdseye View of GraphQL
Net Ninja
6 GraphQL Tutorial #3 - Project (stack) Overview
GraphQL Tutorial #3 - Project (stack) Overview
Net Ninja
7 GraphQL Tutorial #4 - Making Queries (front-end preview)
GraphQL Tutorial #4 - Making Queries (front-end preview)
Net Ninja
8 GraphQL Tutorial #5 - Express App Setup
GraphQL Tutorial #5 - Express App Setup
Net Ninja
9 GraphQL Tutorial #6 - Setting up GraphQL
GraphQL Tutorial #6 - Setting up GraphQL
Net Ninja
10 GraphQL Tutorial #7 - GraphQL Schema
GraphQL Tutorial #7 - GraphQL Schema
Net Ninja
11 GraphQL Tutorial #8 - Root Query
GraphQL Tutorial #8 - Root Query
Net Ninja
12 GraphQL Tutorial #9 - The Resolve Function
GraphQL Tutorial #9 - The Resolve Function
Net Ninja
13 GraphQL Tutorial #10 - Testing Queries in Graphiql
GraphQL Tutorial #10 - Testing Queries in Graphiql
Net Ninja
14 GraphQL Tutorial #11 - GraphQL ID Type
GraphQL Tutorial #11 - GraphQL ID Type
Net Ninja
15 GraphQL Tutorial #12 - Author Type
GraphQL Tutorial #12 - Author Type
Net Ninja
16 GraphQL Tutorial #13 - Type Relations
GraphQL Tutorial #13 - Type Relations
Net Ninja
17 GraphQL Tutorial #14 - GraphQL Lists
GraphQL Tutorial #14 - GraphQL Lists
Net Ninja
18 GraphQL Tutorial #15 - More on Root Queries
GraphQL Tutorial #15 - More on Root Queries
Net Ninja
19 GraphQL Tutorial #16 - Connecting to mLab
GraphQL Tutorial #16 - Connecting to mLab
Net Ninja
20 GraphQL Tutorial #17 - Mongoose Models
GraphQL Tutorial #17 - Mongoose Models
Net Ninja
21 GraphQL Tutorial #18 - Mutations
GraphQL Tutorial #18 - Mutations
Net Ninja
22 GraphQL Tutorial #19 - More on Mutations
GraphQL Tutorial #19 - More on Mutations
Net Ninja
23 GraphQL Tutorial #20 - Updating the Resolve Functions
GraphQL Tutorial #20 - Updating the Resolve Functions
Net Ninja
24 GraphQL Tutorial #21 - GraphQL NonNull
GraphQL Tutorial #21 - GraphQL NonNull
Net Ninja
25 GraphQL Tutorial #22 - Adding a Front-end
GraphQL Tutorial #22 - Adding a Front-end
Net Ninja
26 GraphQL Tutorial #23 - Create React App
GraphQL Tutorial #23 - Create React App
Net Ninja
27 GraphQL Tutorial #24 - Book List Component
GraphQL Tutorial #24 - Book List Component
Net Ninja
28 GraphQL Tutorial #25 - Apollo Client Setup
GraphQL Tutorial #25 - Apollo Client Setup
Net Ninja
29 GraphQL Tutorial #26 - Making Queries from React
GraphQL Tutorial #26 - Making Queries from React
Net Ninja
30 GraphQL Tutorial #27 - Rendering Data in a Component
GraphQL Tutorial #27 - Rendering Data in a Component
Net Ninja
31 GraphQL Tutorial #28 - Add Book Component
GraphQL Tutorial #28 - Add Book Component
Net Ninja
32 GraphQL Tutorial #29 - External Query File
GraphQL Tutorial #29 - External Query File
Net Ninja
33 GraphQL Tutorial #30 - Updating Component State
GraphQL Tutorial #30 - Updating Component State
Net Ninja
34 GraphQL Tutorial #31 - Composing Queries
GraphQL Tutorial #31 - Composing Queries
Net Ninja
35 GraphQL Tutorial #32 - query variables
GraphQL Tutorial #32 - query variables
Net Ninja
36 GraphQL Tutorial #33 - Re-fetching Queries
GraphQL Tutorial #33 - Re-fetching Queries
Net Ninja
37 GraphQL Tutorial #34 - Book Details Component
GraphQL Tutorial #34 - Book Details Component
Net Ninja
38 GraphQL Tutorial #36 - Styling the App
GraphQL Tutorial #36 - Styling the App
Net Ninja
39 GraphQL Tutorial #35 - Making a Single Query
GraphQL Tutorial #35 - Making a Single Query
Net Ninja
40 Build Apps with Vue & Firebase - Udemy Course
Build Apps with Vue & Firebase - Udemy Course
Net Ninja
41 Updated Vue & Firebase Course (Udemy)
Updated Vue & Firebase Course (Udemy)
Net Ninja
42 Vue & Firebase Real-time Chat (Preview) #1 - Intro
Vue & Firebase Real-time Chat (Preview) #1 - Intro
Net Ninja
43 Vue & Firebase Real-time Chat (Preview) #2 - Project Structure
Vue & Firebase Real-time Chat (Preview) #2 - Project Structure
Net Ninja
44 Vue & Firebase Real-time Chat (Preview) #3 - Firestore Setup
Vue & Firebase Real-time Chat (Preview) #3 - Firestore Setup
Net Ninja
45 Vue & Firebase Real-time Chat (Preview) #4 - Welcome Screen
Vue & Firebase Real-time Chat (Preview) #4 - Welcome Screen
Net Ninja
46 Vue & Firebase Real-time Chat (Preview) #5 - Props in Routes
Vue & Firebase Real-time Chat (Preview) #5 - Props in Routes
Net Ninja
47 Vue & Firebase Real-time Chat (Preview) #6 - Route Guards
Vue & Firebase Real-time Chat (Preview) #6 - Route Guards
Net Ninja
48 Vue & Firebase Real-time Chat (Preview) #7 - Chat Window
Vue & Firebase Real-time Chat (Preview) #7 - Chat Window
Net Ninja
49 Vue & Firebase Real-time Chat (Preview) #8 - New Message Component
Vue & Firebase Real-time Chat (Preview) #8 - New Message Component
Net Ninja
50 Object Oriented JavaScript Tutorial #1 - Introduction
Object Oriented JavaScript Tutorial #1 - Introduction
Net Ninja
51 Object Oriented JavaScript Tutorial #2 - Object Literals
Object Oriented JavaScript Tutorial #2 - Object Literals
Net Ninja
52 Object Oriented JavaScript Tutorial #3 - Updating Properties
Object Oriented JavaScript Tutorial #3 - Updating Properties
Net Ninja
53 Object Oriented JavaScript Tutorial #4 - Classes
Object Oriented JavaScript Tutorial #4 - Classes
Net Ninja
54 Object Oriented JavaScript Tutorial #5  - Class Constructors
Object Oriented JavaScript Tutorial #5 - Class Constructors
Net Ninja
55 Object Oriented JavaScript Tutorial #6 - Class Methods
Object Oriented JavaScript Tutorial #6 - Class Methods
Net Ninja
56 Object Oriented JavaScript Tutorial #7 - Method Chaining
Object Oriented JavaScript Tutorial #7 - Method Chaining
Net Ninja
57 Object Oriented JavaScript Tutorial #8 - Class Inheritance
Object Oriented JavaScript Tutorial #8 - Class Inheritance
Net Ninja
58 Object Oriented JavaScript Tutorial #9 - Constructors (under the hood)
Object Oriented JavaScript Tutorial #9 - Constructors (under the hood)
Net Ninja
59 Object Oriented JavaScript Tutorial #10 - Prototype
Object Oriented JavaScript Tutorial #10 - Prototype
Net Ninja
60 Object Oriented JavaScript Tutorial #11 - Prototype Inheritance
Object Oriented JavaScript Tutorial #11 - Prototype Inheritance
Net Ninja

This tutorial teaches how to use Vitest to create spies, track function calls, and test side effects. By the end of the tutorial, you'll be able to write effective unit tests using spies.

Key Takeaways
  1. Create a new spy to spy on the shuffle function
  2. Use the v function to create a spy
  3. Make a new constant to hold the spy
  4. Set the constant equal to the v function
  5. Use the spy to track function calls
  6. Create a spy on the shuffle function using Vitest's spy method
  7. Assert that the shuffle function is called once
  8. Assert that the shuffle function is called before the deal function
  9. Use the mock property to access the invocation call order of the shuffle spy
  10. Compare the global call order of the shuffle and deal functions
💡 Spies are like mock functions but don't change implementation by default, allowing for more flexible and effective unit testing.

Related Reads

Up next
The Godfather of NYC Investment Sales Just Launched an AI-Driven Brokerage. Here's How.
AI for CRE
Watch →