Testing with Mock Implementations in Jest (TypeScript)
Unit testing often requires interacting with external dependencies like APIs, databases, or complex modules. Directly testing against these dependencies can be slow, unreliable (due to network issues or database availability), and can couple your tests to the external system. This challenge focuses on creating mock implementations of dependencies using Jest to isolate your code and ensure focused, reliable unit tests.
Problem Description
You are tasked with creating a mock implementation of a DataFetcher class. The DataFetcher class is responsible for fetching data from an external API. Your goal is to write a Jest test that uses this mock implementation to verify that a function, processData, correctly handles the data returned by the DataFetcher. The processData function should take a DataFetcher instance as a dependency and perform some operations on the fetched data. You need to mock the fetchData method of the DataFetcher to control the data returned to processData and assert that processData behaves as expected given different mock data scenarios.
Key Requirements:
- Create a mock implementation of the
DataFetcherclass using Jest'smockImplementationormockResolvedValuemethods. - Verify that
processDatacallsfetchDataon theDataFetcherinstance. - Verify that
processDataprocesses the mocked data correctly, based on assertions within the function. - Handle potential edge cases where the mocked data might be empty or invalid.
Expected Behavior:
The test should pass if the processData function correctly utilizes the mocked DataFetcher and behaves as expected based on the mocked data. The test should fail if processData does not call fetchData, or if it processes the data incorrectly.
Edge Cases to Consider:
- What happens if the mocked data is an empty array?
- What happens if the mocked data contains unexpected values or types?
- Does
processDatahandle errors gracefully iffetchDatawere to reject (though we're mocking, consider the design)?
Examples
Example 1:
Input:
DataFetcher mock returning: [{ id: 1, name: 'Item 1' }, { id: 2, name: 'Item 2' }]
processData(fetcher) - processData is designed to return the number of items.
Output: 2
Explanation: processData should correctly count the items returned by the mocked DataFetcher.
Example 2:
Input:
DataFetcher mock returning: []
processData(fetcher) - processData is designed to return 0 if no items are found.
Output: 0
Explanation: processData should handle the empty array case gracefully and return 0.
Example 3:
Input:
DataFetcher mock returning: [{ id: 1, name: 'Item 1' }, { id: 2, name: null }]
processData(fetcher) - processData is designed to filter out items with null names.
Output: 1
Explanation: processData should filter out the item with the null name and return the count of valid items.
Constraints
-
The
DataFetcherclass is defined as follows:interface DataItem { id: number; name: string | null; } class DataFetcher { async fetchData(): Promise<DataItem[]> { throw new Error("Method not implemented."); } } -
The
processDatafunction is defined as follows:function processData(fetcher: DataFetcher): number { // Your implementation here return 0; } -
You must use Jest's mocking capabilities to create the mock implementation of
DataFetcher. -
The test should be written in TypeScript.
Notes
- Consider using
jest.mockto mock the entireDataFetcherclass. - Think about how to structure your assertions to verify both the calls to
fetchDataand the resulting data processing. - Focus on isolating the
processDatafunction by controlling its dependency on theDataFetcher. - The
processDatafunction's implementation is not provided; you must write it to be testable with the mock. It should take aDataFetcherinstance and return a number. It should use thefetchDatamethod of theDataFetcherto get data.