使用TestBed,我们可以为依赖注入可用的类创建模拟类。例如,MyButtonClass
可以访问ElementRef
和MyService
,因为它们是通过依赖注入实现的,因此我们可以覆盖它们。我遇到的问题是,要编写Jasmine测试,我必须创建模拟类来覆盖不能通过依赖注入访问的类的方法。
在这种情况下,ScriptLoader.load
会在全局空间中加载ThirdPartyCheckout
。这意味着,当Jasmine读取订阅运算符中的内容时,它可能不可用。出于这个原因,我想首先嘲笑前者然后嘲笑后者。或者也许有不同的解决方法。
如果有人可以建议创建模拟类来覆盖ScriptLoader.load
方法和ThirdPartyCheckout.configure
方法,那就太棒了。
要测试的指令:
@Directive({
selector: '[myButton]'
})
export class MyButtonClass implements AfterViewInit {
private myKey: string;
constructor(private _el: ElementRef, private myService: MyService) {}
ngAfterViewInit() {
this.myService.getKey()
.then((myKey: string) => {
this.myKey = myKey;
ScriptLoader.load('https://thirdpartyurl.js', this._el.nativeElement)
.subscribe(
data => {
this.handeler = ThirdPartyCheckout.configure(<any>{
key: this.myKey
// etc
// and some methods go here
});
},
error => {
console.log(error);
}
);
});
}
}
这是测试代码:
@Component({
selector: 'test-cmp',
template: ''
})
class TestComponent {}
class mockMyService {
getKey() {
return Promise.resolve('this is a key in real code');
}
}
describe('myButton', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestComponent, MyButtonClass],
providers: [
{provide: MyService, useClass: mockMyService}
]
});
});
describe('ngAfterViewInit', fakeAsync(() => {
const template = '<div><div myButton></div></div>';
TestBed.overrideComponent(TestComponent, {set: {template: template}});
let fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();
tick();
}));
});
答案 0 :(得分:2)
作为一等公民的职能,你可以为其分配一个新职能
let originalFn;
beforeEach(() => {
originalFn = ScriptLoader.load;
});
afterEach(() => {
ScriptLoader.load = originalFn;
});
it('...', fakeAsync(() => {
ScriptLoader.load = (url, el: Element): Observable<string> => {
return Observable.of('HelloSquirrel');
};
...
}));
除此之外,您可能只想考虑使用DI。使用DI的主要原因之一是更好的可测试性。对于ScriptLoader
,只需使方法成为非静态方法,对于第三方lib,只需为其创建抽象服务层。