简体   繁体   中英

How to mock a class method's which is initialized inside another class in typescript using ts mockito?

This is my Class I want to test using mocha-chai test framework in typescript. I am using ts-mockito for mocking.

export class ClassA implements IClassA {

    private classAResource: IClassAResource;

    constructor(){
         this.classAResource= new ClassAResource();
    }

    public async cancel(jobid){
       const job = this.classAResource.getJob(jobid);
       //cancel logic
    }
}

ClassAResource class looks like this,

export class StreamResource implements IStreamResource {

private jobs: Map<string, Job>;

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

public async createJob(): Promise<Job> {
//add the job to map
}

public async getJob(jobid): Promise<Job>{
//return the specified job item from map
}


}

In my test I try to mock ClassAResource's getJob method like this,

const classAResource: IClassAResource = new ClassAResource ();
 const classAResourceSpy = spy(classAResource);

 when(classAResourceSpy.getJob(anyString())).thenResolve(job); 

And I call the ClassA cancel method like this,

classA.cancel(jobid)

I expect the getJob call in cancel method to be mocked and return a job object.

But the test is not behaving according to my expectation. Mock doesnt come into picture and getJob() goes to actual implementation and return undefined.

I read online, this issue is because of the constructor initializations in ClassAResource class.

I removed the constructor and tried and now the getJob mock works.

But I need the constructor to instantiate the map object and ability to maintain the jobs.

Is there some workaround through which I can mock getJob() with constructor in place?

Am I doing something wrong here?

I am kind of relatively new to typescript and ts-mockito and any help is greatly appreciated.

This really has nothing to do with TypeScript specifically, but rather a testability issue due to breaking the Dependency Inversion principle .
Instantiating members in the constructor of the class causes a testability issue, since the control over the instantiation is in the hands of the code under test (aka "unit under test", "class under test", etc.). That means, that you have little to no control over which instance the class you're testing will have.

There are some mocking libraries that allow a "hostile takeover" of the instantiation of certain classes (at least for Java, see PowerMock ), but they should be used very sparingly, if at all, since they contribute to perpetuating the lack of testability.

Instead of instantiating IClassAResource from the constructor of ClassA , you should either get the instance via injection (DI, constructor, setter method, etc.), or at least use a factory/builder. This way your class would become testable and your design will be improved.

In general, you should adhere to all of the SOLID principles, since they are, at least at the moment, considered the most accurate and concise set of good OOP design principles.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM