What is the process for mocking a method from a class that is instantiated within another class using ts mockito in typescript?

I have a specific Class that I want to test using the mocha-chai testing framework in TypeScript. My approach involves incorporating ts-mockito for mocking purposes.

export class MainClass implements IMainClass {

    private mainResource: IMainResource;

    constructor() {
         this.mainResource = new MainResource();
    }

    public async doSomething(input) {
       const data = this.mainResource.getData(input);
       //logic implementation
    }
}

The MainResource class structure is similar to this:

export class DataService implements IDataService {

private dataItems: Map<string, DataItem>;

 constructor(){
 this.dataItems= new Map();
 }

public async retrieveData(): Promise<DataItem> {
//add data items to the map
}

public async getData(dataId): Promise<DataItem>{
//retrieve specified data item from the map
}


}

During my testing phase, I attempted to mock the getData method of MainResource like so:

const mainResource: IMainResource = new MainResource ();
 const mainResourceSpy = spy(mainResource);

 when(mainResourceSpy.getData(anyString())).thenResolve(someData); 

Then, I executed the doSomething method of MainClass in the following manner:

mainClass.doSomething(input)

My expectation was for the getData call within the doSomething method to be mocked and return a specific data object.

Unfortunately, the test results did not align with my expectations. The mock was not utilized, and instead, the getData() function proceeded with its actual implementation, returning undefined.

After researching online, it appears that this issue may be due to the constructor initializations in the MainResource class.

I attempted removing the constructor, which resulted in successful mocking of the getData method.

However, I require the constructor to instantiate the map object and manage the data items effectively.

Is there a workaround that would allow me to mock getData() while retaining the constructor functionality?

Could it be possible that I am making an error somewhere in my code?

I acknowledge that I am relatively new to TypeScript and ts-mockito, thus any guidance would be immensely valued.

Answer №1

The issue at hand is not solely related to TypeScript, but rather stems from a problem with testability caused by violating the Dependency Inversion principle.
When members are instantiated within the constructor of a class, it creates a challenge for testing because the control over instantiation lies with the code being tested, making it difficult to predict which instance the class will have.

While there are mocking libraries like PowerMock that offer ways to take over the instantiation of certain classes, they should be used cautiously as they can further hinder testability.

Rather than creating instances of IClassAResource directly in the constructor of ClassA, it is recommended to obtain the instance through injection (DI, constructor, setter method, etc.), or utilize a factory/builder pattern. This approach makes your class more testable and improves design.

Following all the SOLID principles is essential, as they are considered to be the most reliable and concise guidelines for good OOP design.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Why does tsc produce a compiled file that throws an exception when executed, while ts-node successfully runs the TypeScript file without any issues?

I have written two ts files to test a decorator. Here is the content of index.ts: import { lockMethod } from './dec'; class Person { walk() { console.info(`I am walking`); } @lockMethod run() { console.info(`I am running`); } ...

I can't figure out why I'm getting the error message "Uncaught ReferenceError: process is not defined

I have a react/typescript app and prior to updating vite, my code checked whether the environment was development or production with the following logic: function getEnvironment(): "production" | "development" { if (process.env.NODE_E ...

There is a lint error that is thrown when upgrading the typings file for JQuery version 3.2

I recently encountered an issue in my application where I used the following interface. It worked perfectly with jQuery 2.0: interface JQuery{ data(key: any): any; } However, upon upgrading to jQuery 3.2, the following lint errors were thrown: All decla ...

Explore the functionality of a TypeScript-created Vue component by testing it with Vue-test-utils

In my attempt to validate props with various data types in a Vue component (built using TypeScript), I utilized the Vue-test-utils package. Despite implementing expect().tobe(), there remains an untested line: DropDownList.vue <template> <v-sel ...

Is it possible to create a tuple with additional properties without needing to cast it to any type?

To accommodate both array and object destructuring, I have defined the following `Result` type: type Errors = Record<string, string | null>; type Result = [Errors, boolean] & { errors: Errors; success: boolean }; I attempted to create a result of t ...

What is the method to select and activate the second item in the list within the second unordered list?

This is a unique text that I am using to test the footer element of a website. await page.waitForSelector(".footer-menu", {timeout: 10000}) const unorderedList = await page.locator('.footer-menu:nth-child(1) li:nth-child(2)'); un ...

What is my strategy for testing a middleware that accepts arguments?

Here is the middleware I am working with: function verifyKeys(expectedKeys: string[], req: Request): boolean{ if (expectedKeys.length !== Object.keys(req.body).length) return false; for (const key of expectedKeys) { if (!(key in req.body)) return ...

Show the key and value of a JSON object in a React component

When attempting to parse a JSON data file, I encountered an error message stating: "Element implicitly has an 'any' type because expression of type 'string' can't be used to the index type." The JSON data is sourced locally from a ...

Discovering the optimum route within a 2D array given specific limitations using Dynamic Programming

Hey, I have a query related to dynamic programming (dp) that goes like this: Input: A 2D array of numbers Output: The maximum sum of a path from (0,0) to (n-1,n-1) with the following conditions: You can only move down and right i.e. from (A[i-1][j]) t ...

When exporting a custom ES6 module and importing it into a different local project, you may encounter unexpected outputs such as being undefined or

Currently, I am using TypeScript 3.4.5 and Webpack 4.32.2 on Windows 10 via WSL. My goal is to create a local package of tools that consolidates basic classes into an index file for exporting. However, when I try to import these classes into other project ...

Mapping an array of keys to an array of properties using Typescript

Is there a way to achieve the following: type A = { a: string; b: number; c: boolean }; type B = ["b", "a"]; type C = MapProps<A, B> ?? // [number, string] The solution I have currently is: type C = {[key in B[number]]: A[key]} ...

Capturing page titles accurately for timeonsite tracker in a single-page Angular app is challenging when navigating to other pages

Implemented the timeonsite JS tracker in my Angular web application using HTML tags as shown below, <script type="text/javascript"> var Tos; (function(d, s, id, file) { var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementByI ...

Encountering difficulty importing TypeScript files dynamically within a Deno executable

When attempting to import a file from aws in an exe using its public link based on user input, I am facing difficulties For example, I generated my exe with the command below deno compile --allow-all main.ts Users execute this exe using commands like ./e ...

Unable to execute an Angular 2 application within Visual Studio 2015

I encountered an error while trying to set up an environment on VS 2015 with Angular2. Whenever I run the command "npm start," I receive the following error message. I attempted using "npm cache clean --force" before running "npm start," but the error pers ...

Testing Angular: Implementing Mock Classes and Services using the Any Data Type

When mocking services without using TestBed and instead relying on Fake Classes, is it considered a best practice to use a Mock with the : any data type? If not, errors like missing items/parameters may occur. Although spyOn can be used as an alternative, ...

Can getters and setters be excluded from code coverage reports in Angular projects?

Looking to clean up my coverage reports for the front end portion of an angular project by removing trivial code like getters and setters. I generate my reports using npm run test-sonar -- --coverage, but everything is included in the report when I view ...

Application for conducting tests on the .net framework

In my VS2010 standard unit tests, I am looking to gather all the information including variables with their values, called functions, etc. in a readable format such as XML. How can I achieve this? ...

The TypeScript script does not qualify as a module

Just starting out with TypeScript and encountering a simple issue. I'm attempting to import a file in order to bring in an interface. Here's an example: Parent: import { User } from "@/Users"; export interface Gift { id: number; ...

Error message: When using Vue CLI in conjunction with Axios, a TypeError occurs stating that XX

I recently started working with Vue.js and wanted to set up a Vue CLI project with Axios for handling HTTP requests. I came across this helpful guide which provided a good starting point, especially since I plan on creating a large project that can be reus ...

How can you utilize jest to mock a model in Sequelize?

I'm currently working on incorporating tests into a project. Within my project, I have a model called UserModel.js const { Model, DataTypes } = require('sequelize') const sequelize = require('../../lib/db/config') class User exte ...