Hone logo
Hone
Problems

Mocking Objects in Jest with TypeScript

Testing code that relies on external dependencies (like databases, APIs, or complex services) can be challenging. To isolate your unit tests and focus on the logic of your code, you often need to replace these dependencies with "fake" or "mock" objects. This challenge will guide you through creating and using mock objects in Jest with TypeScript to effectively test your code in isolation.

Problem Description

You are tasked with creating a mock object for a UserService class. This UserService is responsible for fetching user data from an external API. Your goal is to mock this service within a Jest test to verify that your code correctly interacts with it, without actually making a real API call. You need to create a mock UserService that allows you to control the returned data and assert that specific methods are called with the expected arguments.

The UserService class is defined as follows:

class UserService {
  async getUserById(id: number): Promise<string> {
    // In a real implementation, this would fetch from an API
    throw new Error("Not implemented - this is a placeholder");
  }

  async updateUser(id: number, name: string): Promise<void> {
    // In a real implementation, this would update a database
    throw new Error("Not implemented - this is a placeholder");
  }
}

You will be testing a UserController class that depends on the UserService. The UserController has a getUserName method which calls UserService.getUserById and a updateUserName method which calls UserService.updateUser.

class UserController {
  constructor(private userService: UserService) {}

  async getUserName(id: number): Promise<string> {
    return this.userService.getUserById(id);
  }

  async updateUserName(id: number, newName: string): Promise<void> {
    await this.userService.updateUser(id, newName);
  }
}

Your test should:

  1. Create a mock UserService using Jest's mocking capabilities.
  2. Configure the mock to return a specific user name when getUserById is called with a particular ID.
  3. Instantiate a UserController with the mock UserService.
  4. Call the getUserName method of the UserController and assert that the returned value is the mocked user name.
  5. Call the updateUserName method of the UserController and assert that the updateUser method of the mock UserService was called with the correct arguments.

Examples

Example 1:

Input: UserController instance with mocked UserService, getUserName(123)
Output: "Mocked User Name"
Explanation: The mock UserService is configured to return "Mocked User Name" when getUserById(123) is called. The UserController calls getUserById(123) and returns the mocked value.

Example 2:

Input: UserController instance with mocked UserService, updateUserName(456, "New Name")
Output: No return value (void), but assertions verify updateUser was called with (456, "New Name")
Explanation: The UserController calls updateUser(456, "New Name") which in turn calls the mock UserService's updateUser method. The assertion verifies that the correct arguments were passed to the mock.

Constraints

  • You must use Jest's mocking capabilities (jest.mock, mockImplementation, mockResolvedValue).
  • The code must be written in TypeScript.
  • The test should be focused on unit testing the UserController and should not involve any external API calls.
  • The mock UserService should be created and configured within the test itself.

Notes

  • Consider using mockResolvedValue for asynchronous methods to simplify the mock implementation.
  • Pay close attention to the arguments passed to the mocked methods and ensure your assertions verify these correctly.
  • Think about how to structure your test to clearly demonstrate the mocking and verification process. Use descriptive names for your mock functions.
  • Remember to import the necessary Jest modules.
Loading editor...
typescript