这是我要在打字稿中使用mocha-chai测试框架进行测试的班级。 我正在使用ts-mockito进行模拟。
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类如下,
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
}
}
在测试中,我尝试像这样模拟ClassAResource的getJob方法,
const classAResource: IClassAResource = new ClassAResource ();
const classAResourceSpy = spy(classAResource);
when(classAResourceSpy.getJob(anyString())).thenResolve(job);
我这样调用ClassA取消方法,
classA.cancel(jobid)
我希望对cancel方法中的getJob调用进行模拟并返回作业对象。
但是测试未达到我的预期。模拟没有出现,getJob()进入实际实现并返回未定义。
我在线阅读,这个问题是由于ClassAResource类中的构造函数初始化。
我删除了构造函数并尝试了,现在getJob模拟工作了。
但是我需要构造函数来实例化map对象和维护作业的能力。
是否存在一些变通办法,可以通过该变通办法来模拟具有构造函数的getJob()?
我在这里做错什么了吗?
我对打字稿和ts-mockito还是比较陌生,非常感谢您的帮助。
答案 0 :(得分:1)
这确实与TypeScript完全无关,而是由于违反Dependency Inversion principle而引起的可测试性问题。
在类的构造函数中实例化成员会导致可测试性问题,因为对实例化的控制权在被测代码(也就是“被测单元”,“被测类”等)的手中。这意味着,您几乎无法控制要测试的类具有哪个实例。
有些模拟库允许对某些类的实例进行“恶意接管”(至少对于Java,请参见PowerMock),但应尽量少用(如果有的话),因为它们会有所贡献导致缺乏可测试性。
您应该通过注入(DI,构造函数,setter方法等)获取实例,或者至少使用工厂/构建器,而不是从IClassAResource
的构造函数实例化ClassA
。这样,您的班级将成为可测试的,并且您的设计将得到改善。
通常,您应该遵守所有SOLID原则,因为至少在目前,它们被认为是最准确,最简洁的良好OOP设计原则。