我正在重构一个TypeScript方法,以添加一个带有默认值的可选参数。重构的方法是一个核心操作,并且有许多高级操作调用核心函数。先前存在的调用省略了新参数(因此使用默认值),而新的和重构的方法提供了新参数值。简化的版本如下所示:
export class Scratch {
coreOperation(mainArg: string, option: boolean = false) {
// ...
}
private midLevelOperation(mainArg: string) {
this.coreOperation(mainArg + '1');
}
highLevelOperation1(mainArg: string) {
this.midLevelOperation(mainArg);
this.coreOperation(mainArg + '2', true);
}
}
我还更新了高级操作的Jasmine测试。我想断言,高级操作导致核心操作被调用时带有某些参数。测试大致如下所示:
describe('Scratch', () => {
let objectUnderTest: Scratch;
beforeEach(() => {
objectUnderTest = new Scratch();
spyOn(objectUnderTest, 'coreOperation');
});
describe('highLevelOperation1', () => {
it('should call core operation', () => {
objectUnderTest.highLevelOperation1('main');
expect(objectUnderTest.coreOperation).toHaveBeenCalledWith('main1', false);
expect(objectUnderTest.coreOperation).toHaveBeenCalledWith('main2', true);
});
});
});
问题是Jasmine的toHaveBeenCalledWith
不知道第二个参数有默认值。上面代码的错误:
- Expected spy coreOperation to have been called with:
[ 'main1', false ]
but actual calls were:
[ 'main1' ],
[ 'main2', true ].
显然,我可以通过从测试中删除false
参数来通过测试。但是我不希望测试知道调用站点是使用1个参数还是2个参数,特别是对于像这个例子这样的私有库函数。
是否有一种方法可以编写Jasmine匹配器,在省略可选参数和传递默认值时都可以工作?
不幸的是,在Jasmine中没有办法监视默认/可选参数。
这是不可能的有几个原因:
- 默认参数是在
arguments
数组变量中设置的,该变量存在于被调用方法的范围中,它们不是传递到参数中的实际值。 toHaveBeenCalledWith
只能测试调用方法的参数,而不能测试方法决定将其缺失的参数默认为什么值。
要解决这个问题,您可以将目标方法包装在包含option: boolean = false
默认参数的另一个方法中。然后你应该能够检查coreOperation
被调用:
coreOperation(mainArg: string, option: boolean) {
// ...
}
private coreOperationDefaultWrapper(mainArg: string, option: boolean = false) {
this.coreOperationmainArg(mainArg, option);
}
值得注意的是,最好的测试是测试应用程序做了什么,而不是测试它是如何编写的。因此,我强烈建议练习测试默认参数会导致什么行为的心态,而不是检查它们实际上是什么。当然,这并不总是可能的,我希望上面的例子可以帮助你!:)