我有一个我想要测试的方法,在我为两个单独的元素调用document.getElementById的方法中。在过去,我刚刚在document.getElementById方法上创建了一个间谍,并将返回值设置为我选择的模拟元素。但是现在我需要第一次调用间谍返回一个模拟元素,然后下一个调用返回第二个独特元素,我不确定如何实现这一点。
代码背后:
private scrollParentToChild(): void {
let parent: HTMLElement = document.getElementById('.theParent');
let child: HTMLElement = document.getElementById('.theChild');
parent.scrollTop = child.offsetTop;
}
单元测试:
describe('scrollParentToChild', () => {
it('should set the parents scrollTop to the offsetTop of the child', () => {
let parent: any = {
scrollTop: 0
};
let child: any = {
offsetTop: 100
};
spyOn(document, 'getElementById').and.returnValue(parent); // Okay this will return the parent for both calls to document.getElementById now, but how do I make it only return this for the first call and then return child for the second call.
component.scrollParentToChild();
expect(parent.scrollTop).toEqual(child.offsetTop);
}
});
答案 0 :(得分:1)
只要您使用的是较新版本的Jasmine(至少2.4),您就应该能够在Jasmine间谍上利用.and.returnValues(...)
方法。您可以按以下方式使用它:
spyOn(document, 'getElementById').and.returnValues(parent, child}; //note the 's'!
这样,对getElementById
的第一次调用将返回parent
,第二次将返回child
,随后的调用将返回undefined
。
答案 1 :(得分:0)
茉莉花间谍真的很简单,缺乏特色。对于更复杂的场景,可以使用Sinon存根:
const mockedGetElementById = sinon.stub(document, 'getElementById');
mockedGetElementById.withArgs('.theParent').returns(parent);
mockedGetElementById.withArgs('.theChild').returns(child);
...
mockedGetElementById.restore();
可以使用Jasmine间谍手动处理多个调用。可以根据document.getElementById.calls.count()
有条件地返回值,但在这种情况下,它是定义返回值的函数参数,而不是顺序。它会是这样的:
spyOn(document, 'getElementById').and.callFake((id) => {
switch (id) {
case '.theParent':
return parent;
case '.theChild':
return child;
default:
throw new Error('Unexpected call');
}
});
应该注意的是,测试框架是Jasmine。在这种情况下,如果它与Karma一起运行并不重要。