如何用茉莉花在单位测试中模拟super.ngoninit()?如何在基本 /父级方法上创建间谍以仅涵盖派生 /子类代码


export class Parent implements OnInit {
    ngOnInit(): void {
    // huge amount of different services calls
    }
}
export class Child extends Parent implements OnInit {
    ngOnInit(): void {
        super.ngOnInit();
        // a few more functions
    }
}  

如何开发单位测试来涵盖儿童的ngoninit不嘲笑父母ngoninit的所有服务功能?

我的尝试就是这样:

let child: Child;
const mockParent = {
    ngOnInit: jasmine.createSpy('ngOnInit')
};
child = new Child();  // base object is created already
Object.getPrototypeOf(child) = jasmine.createSpy('Parent').and.callFake(() => mockParent);  // so this doesn't work

有一个解决方案如何监视父级函数。

Parent.prototype.ngOnInit = jasmine.createSpy('ngOnInit');

但是,解决方案还不够安全。让我们看看一个示例:

class Mobile {
    sport: string;
  
    setSport(): void {
        this.sport = 'Football';
    }
}
describe('MobileClass', () => {
    const mobile: Mobile = new Mobile();
  
    it('#setSport', () => {
        mobile.setSport();
        expect(mobile.sport).toBe('Football');
    });
});
class Desktop extends Mobile {
    isFootball: boolean;
  
    setSport(): void {
        super.setSport();
        this.isFootball = this.func(this.sport);
    }
  
    func(sp: string): boolean {
        return sp === 'Football' ? true : false;
    }
}
describe('DesktopClass', () => {
    const desktop: Desktop = new Desktop();
  
    it('#setSport', () => {
        Mobile.prototype.setSport = jasmine.createSpy('setSport');
        desktop.sport = 'Basketball';
  
        desktop.setSport();
        expect(Mobile.prototype.setSport).toHaveBeenCalled();
        expect(desktop.isFootball).toBe(false);
    });
    it('#func', () => { 
        // 2 cases covered
        ...
    });
});

上面我们有间谍SetSport基类功能。这两个测试成功通过了。现在,想象一下基础上的一些变化,例如"足球"常数是在基类及其单位测试中变为"网球"。在这种情况下,这两个类的单元测试将成功通过。

让我们拒绝基础阶级嘲笑的想法。我们将有:

describe('DesktopClass', () => {
    const desktop: Desktop = new Desktop();
  
    it('#setSport', () => {
        desktop.setSport();
        expect(desktop.isFootball).toBe(true);
    });
});

在第一种情况下,两种测试都通过了,但是如果我们将"足球"更改为基类及其单位测试的"网球",那么台式机的测试将会失败。当大团队在一个大型项目上工作并在几个文件中进行更改,但忘记了其他问题,这是很普遍的错误。

我想引用埃里克·埃利奥特(Eric Elliott)的最后一篇文章"嘲笑是代码气味",尤其是一些引号:

什么是紧密的耦合?

子类耦合:子类取决于实现和父级的整个层次结构:最紧密的耦合形式在OO设计中可用。

是什么原因导致紧密耦合?

突变与不变性,副作用与纯度/孤立的副作用等

保持基类调用在某个角度违反了单位测试的术语,并且可能需要更多的基础服务服务模拟。我们需要在单独的文件中移动这些模拟以保持干燥。想一想要选择的是两倍:更快的简单代码或针对错误的额外保险。

最新更新