ALL ARTICLES
SHARE

Mock vs Stub: What are the Differences?

author-avatar
Development
10 min read
Contents
Contents

Software testing plays a crucial role in ensuring the quality and reliability of software applications. According to recent industry statistics, 70% of software development effort is allocated to testing, highlighting its significance in the development lifecycle. When it comes to unit testing, using test doubles such as mocks and stubs can greatly enhance the effectiveness of your testing process. But what exactly are mocks and stubs, and how do they differ?

In this article, we’ll explore the key differences between mocks and stubs and discuss when to use each type in your unit testing.

Key Takeaways:

  • Mocks and stubs are types of test doubles used in unit testing to simulate the behavior or state of real objects or components.
  • Mocks are used for behavior verification, ensuring that the correct interactions occur between the tested unit and its dependencies.
  • Stubs are used for state verification and provide predetermined responses to method calls, allowing you to test specific scenarios.
  • The choice between mocks and stubs depends on the specific testing requirements and objectives, and both can be used effectively in different scenarios.

What are Mocks and Stubs?

Mocks and stubs are valuable tools in unit testing known as test doubles. These test doubles are used to simulate the behavior or state of real objects or components that are external to the unit being tested. Mocks and stubs play vital roles in the process of software testing, enabling developers to verify behavior and ensure the correctness of their code.

Whether you need to perform behavior verification or state verification, both mocks and stubs serve as efficient means to achieve these objectives. By simulating the interactions with external dependencies, mocks, and stubs help isolate units of code and facilitate thorough testing.

While they share similarities as test doubles, it’s important to understand the distinctions between mocks and stubs to utilize them effectively in your unit testing efforts. In the following sections, we will explore the key differences and determine when to use each type in specific scenarios.

The Key Differences between Mocks and Stubs

When it comes to creating effective unit tests, understanding the differences between mocks and stubs is crucial. While both mocks and stubs serve as test doubles to simulate the behavior or state of real objects or components, they have distinct characteristics that make them suitable for different testing scenarios.

Implementation and Dependency Verification

One key difference between mocks and stubs lies in implementation and dependency verification. Mocks are used to verify the correct interaction between objects by simulating the behavior and expectations of the dependencies. They set up predefined expectations and allow you to verify if the interactions occur as expected. On the other hand, stubs provide predetermined responses to specific method calls, allowing you to control the output of the tested unit.

Simulating Real-World Scenarios

Mocks and stubs also differ in their ability to simulate real-world scenarios. While mocks focus on behavior verification, stubs focus on state verification. Mocks allow you to verify whether specific interactions have occurred, while stubs enable you to test specific outcomes based on pre-defined responses.

Test Complexity and Object Dependencies

Another significant difference between mocks and stubs is their usage in testing complex units and handling object dependencies. Mocks are often used in more complex test cases that involve multiple dependencies and interactions. They allow for fine-grained control over the expected behavior, making them suitable for testing intricate systems. Stubs, on the other hand, are simpler and are often used when testing isolated units with minimal dependencies.

Flexibility and Test Isolation

Mocks and stubs also differ in terms of flexibility and test isolation. Mocks provide greater flexibility by allowing you to specify the expected behavior and interactions of dependencies, making them ideal for highly dynamic scenarios. Stubs, on the other hand, are more static, providing predictable responses and isolating the unit being tested from its dependencies to ensure reliable results.

Mock

Stub

Mocks are objects that have expectations about the order and number of times they will be called. They are used to verify behavior by checking if the expected interactions occurred during the unit test.

Stubs, on the other hand, provide predefined responses to specific method calls. They are used to simulate the behavior of dependencies and control the output of those dependencies, enabling developers to test different scenarios.

Mocks focus on the verification of behavior, ensuring that the correct methods are called with the expected parameters.

Stubs focus on providing predetermined responses to method calls without verifying the order or number of times they occur. They allow developers to control the state of the system being tested.

Mocks are typically used when you want to verify specific interactions with dependencies and ensure that the unit being tested acts correctly in response.

Stubs are commonly used when you need to isolate the unit being tested from its dependencies, controlling the behavior and output to create specific test scenarios.

Example of a Mock in Jest

Let’s say we have a function sendEmail that we want to test, which relies on an email service object emailService with a method send. We’ll use a mock to verify the interaction between sendEmail and emailService.

/ emailService.js
module.exports = {
  send: (to, subject, message) => {
    // Imagine this sends an email
  }
};
// sendEmail.js
const emailService = require(‘./emailService’);
function sendEmail(to, subject, message) {
  emailService.send(to, subject, message);
  return `Email sent to ${to}`;
}
// sendEmail.test.js
const emailService = require(‘./emailService’);
jest.mock(‘./emailService’); // Automatically mocks the emailService
test(‘sendEmail should call emailService.send’, () => {
  const to = ‘test@example.com’;
  const subject = ‘Hello’;
  const message = ‘Hello, world!’;
  sendEmail(to, subject, message);
  expect(emailService.send).toHaveBeenCalledWith(to, subject, message);
});
/ emailService.js
module.exports = {
  send: (to, subject, message) => {
    // Imagine this sends an email
  }
};
// sendEmail.js
const emailService = require(‘./emailService’);
function sendEmail(to, subject, message) {
  emailService.send(to, subject, message);
  return `Email sent to ${to}`;
}
// sendEmail.test.js
const emailService = require(‘./emailService’);
jest.mock(‘./emailService’); // Automatically mocks the emailService
test(‘sendEmail should call emailService.send’, () => {
  const to = ‘test@example.com’;
  const subject = ‘Hello’;
  const message = ‘Hello, world!’;
  sendEmail(to, subject, message);
  expect(emailService.send).toHaveBeenCalledWith(to, subject, message);
});

 

In this test, jest.mock(‘./emailService’) creates a mock of the emailService module. We then verify that sendEmail correctly calls emailService.send with the expected parameters using expect(emailService.send).toHaveBeenCalledWith(to, subject, message).

Example of a Stub in Jest

Now, let’s consider a scenario where we need to test a function fetchUserProfile that makes a call to a database to retrieve user data. We’ll use a stub to simulate the database response.

// emailService.js
module.exports = {
  send: (to, subject, message) => {
    // Imagine this sends an email
  }
};
// sendEmail.js
const emailService = require(‘./emailService’);
function sendEmail(to, subject, message) {
  emailService.send(to, subject, message);
  return `Email sent to ${to}`;
}
// sendEmail.test.js
const emailService = require(‘./emailService’);
jest.mock(‘./emailService’); // Automatically mocks the emailService
test(‘sendEmail should call emailService.send’, () => {
  const to = ‘test@example.com’;
  const subject = ‘Hello’;
  const message = ‘Hello, world!’;
  sendEmail(to, subject, message);
  expect(emailService.send).toHaveBeenCalledWith(to, subject, message);
});
2:53
// userService.js
async function fetchUserProfile(userId) {
  // Imagine this fetches user profile from a database
}
// userService.test.js
const userService = require(‘./userService’);
test(‘fetchUserProfile should return user data for the given userId’, async () => {
  // Stubbing the database call response
  userService.fetchUserProfile = jest.fn().mockResolvedValue({
    userId: ‘123’,
    username: ‘john_doe’,
    email: ‘john@example.com’
  });
  const profile = await userService.fetchUserProfile(‘123’);
  expect(profile).toEqual({
    userId: ‘123’,
    username: ‘john_doe’,
    email: ‘john@example.com’
  });
});
// emailService.js
module.exports = {
  send: (to, subject, message) => {
    // Imagine this sends an email
  }
};
// sendEmail.js
const emailService = require(‘./emailService’);
function sendEmail(to, subject, message) {
  emailService.send(to, subject, message);
  return `Email sent to ${to}`;
}
// sendEmail.test.js
const emailService = require(‘./emailService’);
jest.mock(‘./emailService’); // Automatically mocks the emailService
test(‘sendEmail should call emailService.send’, () => {
  const to = ‘test@example.com’;
  const subject = ‘Hello’;
  const message = ‘Hello, world!’;
  sendEmail(to, subject, message);
  expect(emailService.send).toHaveBeenCalledWith(to, subject, message);
});
2:53
// userService.js
async function fetchUserProfile(userId) {
  // Imagine this fetches user profile from a database
}
// userService.test.js
const userService = require(‘./userService’);
test(‘fetchUserProfile should return user data for the given userId’, async () => {
  // Stubbing the database call response
  userService.fetchUserProfile = jest.fn().mockResolvedValue({
    userId: ‘123’,
    username: ‘john_doe’,
    email: ‘john@example.com’
  });
  const profile = await userService.fetchUserProfile(‘123’);
  expect(profile).toEqual({
    userId: ‘123’,
    username: ‘john_doe’,
    email: ‘john@example.com’
  });
});

 

In this example, jest.fn().mockResolvedValue({…}) is used to stub the fetchUserProfile function, simulating a successful database call that returns a user profile. The test verifies that fetchUserProfile returns the correct data structure for the given userId.

These examples demonstrate how mocks and stubs can be effectively used in JavaScript testing with Jest to simulate dependencies and verify interactions or outcomes in your tests

When to Use Mocks or Stubs in Unit Testing

The choice between using mocks or stubs in unit testing depends on the specific testing requirements and objectives. Here are some scenarios where mocks or stubs can be used effectively:

Using Mocks

  1. Verifying behavior: Mocks are commonly used when you want to verify that certain methods or functions are called with the expected parameters or in the correct sequence.
  2. Testing interactions: Mocks are ideal for testing interactions between different components or objects, allowing you to ensure that one component is correctly calling and interacting with another.
  3. Simulating complex responses: Mocks can be used to simulate complex responses from external dependencies, such as API calls or database queries, allowing you to test the behavior of your unit in different scenarios.

Using Stubs

  1. Testing specific states: Stubs are useful when you want to test specific states or conditions of your unit, without worrying about the internal behavior or implementation details.
  2. Isolating dependencies: Stubs can be used to isolate dependencies that are not directly relevant to the unit being tested, ensuring that your tests focus on the specific functionality you want to verify.
  3. Simplifying test setup: Stubs can simplify the setup of your unit tests by providing predefined responses or behaviors, reducing the complexity of mocking complex interactions.

When to Use Both

In some cases, a combination of mocks and stubs may be necessary to achieve comprehensive unit test coverage. By using mocks to verify behavior and stubs to isolate dependencies, you can create robust and thorough tests that encompass all aspects of your unit’s functionality.

Scenario

Use Mock

Use Stub

Use Both

Verifying method calls

  

Testing interactions

  

Simulating complex responses

  

Testing specific states

 

 

Isolating dependencies

 

 

Simplifying test setup

 

 

Comprehensive coverage

  

Conclusion

Understanding the differences between mocks and stubs and choosing the right test double for your unit testing needs is crucial for creating effective and reliable tests.

Choosing the right test double involves understanding the distinct characteristics of mocks and stubs. Mocks are used to verify interactions between objects, ensuring that the correct methods are called and parameters are passed. On the other hand, stubs are used to provide predetermined responses or simulate specific conditions without necessarily verifying interactions. By choosing the appropriate test double, you can accurately test your software and identify any potential issues or bugs.

If you are looking for an extra pair of eyes to review your product, read more about Flatirons’ quality assurance services.

FAQ

What is the difference between a mock and a stub?

A stub is an object used to provide canned answers to method calls, while a mock is pre-programmed with expectations that form a set of specifications that the code under test must satisfy.

When should I use a mock object?

You should use a mock object when you want to verify the behavior of the code under test, also known as behavior verification.

What is a test double?

Test double is a generic term for any case where you replace a production object for testing purposes. Examples of test doubles are mocks, stubs, fakes, and dummies.

How do I use a stub?

You use a stub to provide canned answers to method calls during a test. Stubs are useful when you want to isolate the code under test from its dependencies.

What is a fake object in testing?

In testing, a fake object stands for a simplified, working implementation of a particular interface or class. It is designed to mimic the functionality of the real object for testing purposes.

What is the purpose of using stubs and mocks in testing?

Stubs and mocks are used in testing to isolate the code under test from its dependencies, simulate certain behaviors, and verify the interaction and behavior of the code being tested.

What is the role of a mock or a stub in integration testing?

In integration testing, a mock or a stub is used to simulate the behavior of external components and dependencies, thereby ensuring that the code under test interacts correctly with its surroundings.

author-avatar
More ideas.
Development

Software Development in Colombia: Ultimate Guide in 2024

Flatirons

May 03, 2024
Development

Vital Software Development Outsourcing Statistics for 2024

Flatirons

May 02, 2024
Development

Fintech Software Development Outsourcing

Flatirons

May 01, 2024
Development

The Best Languages for Web Development: Guide in 2024

Flatirons

Apr 30, 2024
Development

Software Development in South America: A Guide

Flatirons

Apr 29, 2024
Development

Latin America Software Outsourcing: A Guide in 2024

Flatirons

Apr 28, 2024
Development

Software Development in Colombia: Ultimate Guide in 2024

Flatirons

May 03, 2024
Development

Vital Software Development Outsourcing Statistics for 2024

Flatirons

May 02, 2024
Development

Fintech Software Development Outsourcing

Flatirons

May 01, 2024
Development

The Best Languages for Web Development: Guide in 2024

Flatirons

Apr 30, 2024
Development

Software Development in South America: A Guide

Flatirons

Apr 29, 2024
Development

Latin America Software Outsourcing: A Guide in 2024

Flatirons

Apr 28, 2024