NagRock / ts-mockito

Mocking library for TypeScript
MIT License
974 stars 93 forks source link

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

Closed shaiksyedali closed 5 years ago

shaiksyedali commented 5 years ago

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
    }
}

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.

NagRock commented 5 years ago

Hi @shaiksyedali

This is not a problem with mocking, but with providing dependencies into your class. If you instantiate object by yourself in constructor then you don't have access to it as it is private field.

You can make this field public and then use spy on this field. But this is not recommended. We should not expose anything for tests purposes.

Better solution is to provide classAResource to ClassA via constructor.