Mocking and Stubbing JavaScript Dependencies for Unit Tests
Jul 16, 2025 am 12:46 AMThe difference between Mocking and Stubbing is that stub only replaces the function return value, while mock also verifies the call. Stubbing makes the function return a preset value and does not care about the call method; Mocking checks whether the function is called correctly, including the number of times and parameters. Common tools include Jest, Sinon.js, etc. Jest is suitable for general projects, and Sinon control is more refined. Common practices include mocking the entire module, replacing specific functions, controlling return values, and verifying the call situation. Best practice is to avoid excessive mocking, prioritize real data, keep mocking simple and clean up in time. It can also simulate the delayed test loading status. Rational use can improve test stability and coverage, but it is necessary to prevent abuse from affecting maintenance.
When writing JavaScript unit tests, we often need to deal with dependencies. For example, calling external APIs, accessing databases, or using certain objects in the browser environment (such as localStorage
or fetch
). These dependencies can make the test unstable or difficult to cover all situations. At this time, mocking and stubbing are needed to simulate these behaviors.

They are not intended to replace real logic, but to make the test focus more on the behavior of the current module rather than the external code it depends on.
What are Mocking and Stubbing?
These two words are often mixed, but there are actually differences:

- Stubbing is the behavior of replacing a function or method, so that it returns a preset value without caring about how it is called.
- For example: Fix the return value
fetchData()
to{ status: 'ok' }
- For example: Fix the return value
- Mocking goes a step further, not only replacing the behavior, but also verifying whether the function is called correctly.
- For example: Check whether
fetchData()
has been called twice and whether the parameters are correct
- For example: Check whether
Simply put, stub focuses on "what to return", and mock focuses on "how to be called".
Common scenarios and tool selection
In JavaScript testing, common tools include Jest, Sinon.js, TestDouble.js, etc. Jest has a simple mocking built-in feature, which is suitable for most projects; while Sinon is more powerful and suitable for scenarios that require fine control.

Here are some common scenarios and practices:
Replace module dependencies
If you are testing a module A, which introduces module B, you can use Jest's jest.mock()
to mock the entire module:
jest.mock('./myModule', () => ({ fetchData: jest.fn(() => Promise.resolve({ data: 'mocked' })) }));
Replace a function
Sometimes you just want to mock a function instead of the entire module:
const originalFetch = window.fetch; window.fetch = jest.fn(() => Promise.resolve(new Response('{"ok":true}')));
Control function returns value
Use .mockReturnValue()
to easily control the return content of the function:
myFunction.mockReturnValue(42);
Verify the call situation
The mock function can also help you check the number of calls and parameters:
expect(myFunction).toHaveBeenCalled(); expect(myFunction).toHaveBeenCalledWith('arg1');
Notes and best practices
Although mock is convenient, using too much can easily make the tests fragile or be too tightly coupled to implementation details. The following points can help you avoid these problems:
- Don't over-mock : only mock those parts that are uncontrollable or can cause side effects.
- Priority is given to using real data structures : for example, when testing array operations, just pass in the array directly, without mocking.
- Keep mocks simple and intuitive : complex mocks are prone to errors and difficult to maintain.
- Pay attention to cleaning up mock : especially when used in beforeEach/afterEach, remember to restore it to its original state.
In addition, some developers prefer to automatically clear mock's call history after each test:
afterEach(() => { jest.clearAllMocks(); });
Tips: Add delay to mock to simulate real requests
If you want to simulate the delay of network requests, you can write this:
fetchData.mockImplementation(() => new Promise(resolve => setTimeout(resolve, 100)) );
This can help you test loading state or error handling logic.
Basically that's it. Mocking and stubbing are very practical means in unit testing. Mastering them well can make the test more stable and easier to cover boundary situations. However, be careful not to abuse it, otherwise it will affect maintainability.
The above is the detailed content of Mocking and Stubbing JavaScript Dependencies for Unit Tests. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

There are three common ways to initiate HTTP requests in Node.js: use built-in modules, axios, and node-fetch. 1. Use the built-in http/https module without dependencies, which is suitable for basic scenarios, but requires manual processing of data stitching and error monitoring, such as using https.get() to obtain data or send POST requests through .write(); 2.axios is a third-party library based on Promise. It has concise syntax and powerful functions, supports async/await, automatic JSON conversion, interceptor, etc. It is recommended to simplify asynchronous request operations; 3.node-fetch provides a style similar to browser fetch, based on Promise and simple syntax

JavaScript data types are divided into primitive types and reference types. Primitive types include string, number, boolean, null, undefined, and symbol. The values are immutable and copies are copied when assigning values, so they do not affect each other; reference types such as objects, arrays and functions store memory addresses, and variables pointing to the same object will affect each other. Typeof and instanceof can be used to determine types, but pay attention to the historical issues of typeofnull. Understanding these two types of differences can help write more stable and reliable code.

Hello, JavaScript developers! Welcome to this week's JavaScript news! This week we will focus on: Oracle's trademark dispute with Deno, new JavaScript time objects are supported by browsers, Google Chrome updates, and some powerful developer tools. Let's get started! Oracle's trademark dispute with Deno Oracle's attempt to register a "JavaScript" trademark has caused controversy. Ryan Dahl, the creator of Node.js and Deno, has filed a petition to cancel the trademark, and he believes that JavaScript is an open standard and should not be used by Oracle

CacheAPI is a tool provided by the browser to cache network requests, which is often used in conjunction with ServiceWorker to improve website performance and offline experience. 1. It allows developers to manually store resources such as scripts, style sheets, pictures, etc.; 2. It can match cache responses according to requests; 3. It supports deleting specific caches or clearing the entire cache; 4. It can implement cache priority or network priority strategies through ServiceWorker listening to fetch events; 5. It is often used for offline support, speed up repeated access speed, preloading key resources and background update content; 6. When using it, you need to pay attention to cache version control, storage restrictions and the difference from HTTP caching mechanism.

Promise is the core mechanism for handling asynchronous operations in JavaScript. Understanding chain calls, error handling and combiners is the key to mastering their applications. 1. The chain call returns a new Promise through .then() to realize asynchronous process concatenation. Each .then() receives the previous result and can return a value or a Promise; 2. Error handling should use .catch() to catch exceptions to avoid silent failures, and can return the default value in catch to continue the process; 3. Combinators such as Promise.all() (successfully successful only after all success), Promise.race() (the first completion is returned) and Promise.allSettled() (waiting for all completions)

JavaScript array built-in methods such as .map(), .filter() and .reduce() can simplify data processing; 1) .map() is used to convert elements one to one to generate new arrays; 2) .filter() is used to filter elements by condition; 3) .reduce() is used to aggregate data as a single value; misuse should be avoided when used, resulting in side effects or performance problems.

JavaScript's event loop manages asynchronous operations by coordinating call stacks, WebAPIs, and task queues. 1. The call stack executes synchronous code, and when encountering asynchronous tasks, it is handed over to WebAPI for processing; 2. After the WebAPI completes the task in the background, it puts the callback into the corresponding queue (macro task or micro task); 3. The event loop checks whether the call stack is empty. If it is empty, the callback is taken out from the queue and pushed into the call stack for execution; 4. Micro tasks (such as Promise.then) take precedence over macro tasks (such as setTimeout); 5. Understanding the event loop helps to avoid blocking the main thread and optimize the code execution order.

Event bubbles propagate from the target element outward to the ancestor node, while event capture propagates from the outer layer inward to the target element. 1. Event bubbles: After clicking the child element, the event triggers the listener of the parent element upwards in turn. For example, after clicking the button, it outputs Childclicked first, and then Parentclicked. 2. Event capture: Set the third parameter to true, so that the listener is executed in the capture stage, such as triggering the capture listener of the parent element before clicking the button. 3. Practical uses include unified management of child element events, interception preprocessing and performance optimization. 4. The DOM event stream is divided into three stages: capture, target and bubble, and the default listener is executed in the bubble stage.
