Home Web Front-end JS Tutorial Before TDD: Why you need to know what Mocks, Stubs, and Spies are?

Before TDD: Why you need to know what Mocks, Stubs, and Spies are?

Jan 10, 2025 am 09:23 AM

Before TDD: Why you need to know what Mocks, Stubs, and Spies are?

Hello, everyone! Today, I bring a topic that I believe is very interesting. I know there are dozens of articles online discussing TDD, BDD, design patterns for testing, how to write tests, and many other related topics. However, I see very few articles explaining more basic terms within the testing universe—those functions we often use but don’t always fully understand what they mean or how they behave. If you’re just starting to learn about testing and don’t know exactly what the library functions do, this article is for you. Enjoy the read!

What are mocks?

The first thing you might come across as soon as you start writing tests is mocks. Sometimes you already use them but don’t know exactly what they mean. So, let’s dive in.

Mocks are primarily used in unit testing. They are tools used to simulate content, objects, or responses that usually come from an external dependency, or when you need the content to have specific information.

Imagine you’re testing a movie recommendation system. This system fetches a list of movies from an API and returns it to you.

The problem is: if every time you run the tests, the real API is called, it could be slow and inconsistent (movies might vary, or the API could be down), making the tests unreliable.

Alright, Leo, I get the problem, but how does a mock solve this? Well, it’s simple: instead of calling the API, you use its response as a static list of movies. It’s basically “faking” the API response with that list of movies.

In the movie system example, if you want to test a function called fetchMoviesFromAPI() that uses the API to fetch movies, you can create a mock to simulate the API response like this:

// This is the mock
const MOVIES_FROM_API = [
    {
        id: 1,
        name: "Interstellar"
    },
    {
        id: 2,
        name: "Nosferatu"
    }
]

// Here, we’re telling fetchMoviesFromAPI to return our mock instead of calling the real API. This is a stub, which you’ll learn about in the next section.
const fetchMoviesFromAPI = jest.fn().mockResolvedValue(MOVIES_FROM_API)

;(async () => {
    {
        const expectedMovies = MOVIES_FROM_API
        const movies = await fetchMoviesFromAPI()

        expect(movies).toEqual(MOVIES_FROM_API)
    }
})()
Copy after login
Copy after login
Copy after login

With mocks, your tests become more efficient since they don’t depend on external services. Moreover, they gain reliability because you have total control over the returns, allowing the focus to remain on validating the functionality without worrying about potential API instabilities or downtime.

Mocks are static objects that simulate responses from calls or other objects needed for testing.

In the end, it’s like testing a car without using real gasoline. You create a controlled environment to ensure the engine is working before taking it out on the road.

I get mocks, now what are stubs?

Stubs are also testing tools but serve a slightly different purpose. They replace the behavior of functions with something predetermined, often using mocks to return specific values.

Stubs replace the function’s behavior. For example, when I access that movie API, the function won’t make the real call but will look at our mock (the static list of movies).

They also serve as a reminder that our tests shouldn’t depend on external services or the internet.

Let me give you some context: imagine you’re testing an application that calculates the total value of an online purchase. The calculation includes fees fetched from an external service. Every time you run the test, this calculation needs to be done, meaning the external service would need to be called. This could result in a slow, unstable, costly (because the external service might charge per request), and inconsistent test (values could change).

Using a stub, you’ll replace the real service call with a fixed, predefined value (yes, a mock). Instead of calling the fee service, you say: “Always return the value 10 as the fee.”

Imagine you want to test the function calculateTotalPurchase() that sums up the cart items’ values and adds the shipping fee. Using stubs, you replace the shipping fee service with a value that always returns “10” as the shipping fee. Like this:

// This is the mock
const MOVIES_FROM_API = [
    {
        id: 1,
        name: "Interstellar"
    },
    {
        id: 2,
        name: "Nosferatu"
    }
]

// Here, we’re telling fetchMoviesFromAPI to return our mock instead of calling the real API. This is a stub, which you’ll learn about in the next section.
const fetchMoviesFromAPI = jest.fn().mockResolvedValue(MOVIES_FROM_API)

;(async () => {
    {
        const expectedMovies = MOVIES_FROM_API
        const movies = await fetchMoviesFromAPI()

        expect(movies).toEqual(MOVIES_FROM_API)
    }
})()
Copy after login
Copy after login
Copy after login

This simplifies the test and ensures its reproducibility, meaning it will always work the same way. Moreover, stubs help isolate the test, eliminating the need to worry about the state or availability of the fee API.

In summary, it’s like testing a cake recipe using a measuring cup that always says 200ml of milk instead of measuring the actual amount of milk. This way, you’re only testing if you can mix the ingredients without worrying about whether the milk is being measured correctly.

Mocks, stubs... and finally, what are spies?

We’ve explored mocks, which simulate objects, and stubs, which mimic function behaviors. Now, let’s talk about spies: what exactly do they do?

Spies monitor functions, recording how many times they were called, what parameters they received, and the results of each execution. They allow you to observe the function’s behavior without altering it, ensuring everything is working as expected.

Imagine you’re testing the notification module of your project. Every time an order is completed, the system should send a message to the customer and log an entry. In this case, you only want to make sure these actions are performed but don’t want to replace any of them. With a spy, you monitor these functions without altering their behavior. This allows you to see:

  • If the function was called
  • How many times it was called
  • What arguments it received

For example, if you want to test the completeOrder() function that sends a notification to the customer and logs the entry, with a spy, you can verify:

  • If the notification function was called
  • If the log function was called
  • What arguments these functions received.
// This is the mock
const MOVIES_FROM_API = [
    {
        id: 1,
        name: "Interstellar"
    },
    {
        id: 2,
        name: "Nosferatu"
    }
]

// Here, we’re telling fetchMoviesFromAPI to return our mock instead of calling the real API. This is a stub, which you’ll learn about in the next section.
const fetchMoviesFromAPI = jest.fn().mockResolvedValue(MOVIES_FROM_API)

;(async () => {
    {
        const expectedMovies = MOVIES_FROM_API
        const movies = await fetchMoviesFromAPI()

        expect(movies).toEqual(MOVIES_FROM_API)
    }
})()
Copy after login
Copy after login
Copy after login

To conclude, it’s like placing a camera to observe what a chef does in the kitchen. You don’t interfere with what they’re doing; you just check if they’re following the recipe correctly.

So, that’s it! You’ve learned and understood the terms mocks, stubs, and spies, which are fundamental elements for creating reliable and efficient tests. Now you can continue deepening your studies. See you there, goodbye!

The above is the detailed content of Before TDD: Why you need to know what Mocks, Stubs, and Spies are?. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

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

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

Java Tutorial
1664
14
PHP Tutorial
1268
29
C# Tutorial
1246
24
The Evolution of JavaScript: Current Trends and Future Prospects The Evolution of JavaScript: Current Trends and Future Prospects Apr 10, 2025 am 09:33 AM

The latest trends in JavaScript include the rise of TypeScript, the popularity of modern frameworks and libraries, and the application of WebAssembly. Future prospects cover more powerful type systems, the development of server-side JavaScript, the expansion of artificial intelligence and machine learning, and the potential of IoT and edge computing.

JavaScript Engines: Comparing Implementations JavaScript Engines: Comparing Implementations Apr 13, 2025 am 12:05 AM

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

Python vs. JavaScript: The Learning Curve and Ease of Use Python vs. JavaScript: The Learning Curve and Ease of Use Apr 16, 2025 am 12:12 AM

Python is more suitable for beginners, with a smooth learning curve and concise syntax; JavaScript is suitable for front-end development, with a steep learning curve and flexible syntax. 1. Python syntax is intuitive and suitable for data science and back-end development. 2. JavaScript is flexible and widely used in front-end and server-side programming.

JavaScript: Exploring the Versatility of a Web Language JavaScript: Exploring the Versatility of a Web Language Apr 11, 2025 am 12:01 AM

JavaScript is the core language of modern web development and is widely used for its diversity and flexibility. 1) Front-end development: build dynamic web pages and single-page applications through DOM operations and modern frameworks (such as React, Vue.js, Angular). 2) Server-side development: Node.js uses a non-blocking I/O model to handle high concurrency and real-time applications. 3) Mobile and desktop application development: cross-platform development is realized through ReactNative and Electron to improve development efficiency.

How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration) How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration) Apr 11, 2025 am 08:22 AM

This article demonstrates frontend integration with a backend secured by Permit, building a functional EdTech SaaS application using Next.js. The frontend fetches user permissions to control UI visibility and ensures API requests adhere to role-base

Building a Multi-Tenant SaaS Application with Next.js (Backend Integration) Building a Multi-Tenant SaaS Application with Next.js (Backend Integration) Apr 11, 2025 am 08:23 AM

I built a functional multi-tenant SaaS application (an EdTech app) with your everyday tech tool and you can do the same. First, what’s a multi-tenant SaaS application? Multi-tenant SaaS applications let you serve multiple customers from a sing

From C/C   to JavaScript: How It All Works From C/C to JavaScript: How It All Works Apr 14, 2025 am 12:05 AM

The shift from C/C to JavaScript requires adapting to dynamic typing, garbage collection and asynchronous programming. 1) C/C is a statically typed language that requires manual memory management, while JavaScript is dynamically typed and garbage collection is automatically processed. 2) C/C needs to be compiled into machine code, while JavaScript is an interpreted language. 3) JavaScript introduces concepts such as closures, prototype chains and Promise, which enhances flexibility and asynchronous programming capabilities.

JavaScript and the Web: Core Functionality and Use Cases JavaScript and the Web: Core Functionality and Use Cases Apr 18, 2025 am 12:19 AM

The main uses of JavaScript in web development include client interaction, form verification and asynchronous communication. 1) Dynamic content update and user interaction through DOM operations; 2) Client verification is carried out before the user submits data to improve the user experience; 3) Refreshless communication with the server is achieved through AJAX technology.

See all articles