当两个方法名称相同但参数不同时使用 sinon.spy
using sinon.spy when two methods have the same name but different arguments
我正在尝试在一个对象上使用 sinon.spy(),该对象有两个名为 draw 的方法(名称相同但参数不同),如下所示:
const spy = sinon.spy(obj,'draw')
当我尝试使用 expect(spy.calledOnceWith(expectedArgument)).toBeTruthy()
测试间谍时,其中 expectedArgument 与 draw 的函数定义之一给出的类型匹配,我收到一条错误消息,指出该参数不可分配给指定的类型draw 的另一个函数声明。在这种情况下,有没有一种方法可以指定 header/declaration 我在创建间谍时指的是哪个函数,以便参数匹配?
YES,您需要对 sinon 间谍进行双重断言以避免 typescript lint 错误。这个 lint 错误是因为 sinon spy 自动应用已知的最后一个定义。您需要提供将在测试中使用的正确断言。
例如:我在文件add.ts中添加了class。如果两个输入都是数字,那么 process 方法将尝试将它们相加。如果两个输入都是字符串,那么 process 方法将尝试连接字符串。其他的会产生TypeError.
class Add {
process(a: number, b: number): number;
process(a: string, b: string): string;
process(a: any, b: any):number|string|Error {
if (typeof a === 'number' && typeof b === 'number') {
return a + b;
} else if (typeof a === 'string' && typeof b === 'string') {
return `${a}${b}`;
}
throw new TypeError('Incorrect type to process');
}
}
export default Add;
我有测试文件:add.spec.ts 将测试所有条件。
import sinon from 'sinon';
import { expect } from 'chai';
import Add from '../src/add';
describe('Add', () => {
afterEach(() => {
sinon.restore();
});
it('should process number', () => {
const obj = new Add();
const a = 1;
const b = 2;
// Sinon spy automatically try to apply the last definition known, which is:
// sinon.SinonSpy<[a: string, b: string], string>
// So we need to do type assertions to:
// sinon.SinonSpy<[a: number, b: number], number>
const spy = sinon.spy(obj, 'process') as unknown as sinon.SinonSpy<[a: number, b: number], number>;
const result = obj.process(a, b);
expect(result).to.equal(a + b);
// This line: linter will not complain.
expect(spy.calledOnceWith(a, b)).to.equal(true);
});
it('should process string', () => {
const obj = new Add();
const a = '1';
const b = '2';
// Sinon spy has automatically apply the correct definition.
const spy = sinon.spy(obj, 'process'); // as unknown as sinon.SinonSpy<[a: string, b: string], string>;
const result = obj.process(a, b);
expect(result).to.equal(`${a}${b}`);
// This line: linter will not complain.
expect(spy.calledOnceWith(a, b)).to.equal(true);
});
it('should throw error for invalid type', () => {
const obj = new Add();
const a = 1;
const b = '2';
// Sinon spy automatically try to apply the last definition known, which is:
// sinon.SinonSpy<[a: string, b: string], string>
// So we need to do type assertions to:
// sinon.SinonSpy<[a: any, b: any], Error>
const spy = sinon.spy(obj, 'process') as unknown as sinon.SinonSpy<[a: any, b: any], Error>;
// We also need to cast obj as any, or there will be lint error:
// The call would have succeeded against this implementation,
// but implementation signatures of overloads are not externally visible.
expect(() => (obj as any).process(a, b)).to.throw(TypeError);
// This line: linter will not complain.
expect(spy.calledOnceWith(a, b)).to.equal(true);
});
});
当我在终端使用 ts-mocha 调用 runner 并使用 nyc 进行覆盖时,我得到:(我的编辑也没有抗议)。
$ npx nyc ts-mocha test/add.spec.ts
Add
✓ should process number
✓ should process string
✓ should throw error for invalid type
3 passing (5ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
add.ts | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
参考:https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions
我正在尝试在一个对象上使用 sinon.spy(),该对象有两个名为 draw 的方法(名称相同但参数不同),如下所示:
const spy = sinon.spy(obj,'draw')
当我尝试使用 expect(spy.calledOnceWith(expectedArgument)).toBeTruthy()
测试间谍时,其中 expectedArgument 与 draw 的函数定义之一给出的类型匹配,我收到一条错误消息,指出该参数不可分配给指定的类型draw 的另一个函数声明。在这种情况下,有没有一种方法可以指定 header/declaration 我在创建间谍时指的是哪个函数,以便参数匹配?
YES,您需要对 sinon 间谍进行双重断言以避免 typescript lint 错误。这个 lint 错误是因为 sinon spy 自动应用已知的最后一个定义。您需要提供将在测试中使用的正确断言。
例如:我在文件add.ts中添加了class。如果两个输入都是数字,那么 process 方法将尝试将它们相加。如果两个输入都是字符串,那么 process 方法将尝试连接字符串。其他的会产生TypeError.
class Add {
process(a: number, b: number): number;
process(a: string, b: string): string;
process(a: any, b: any):number|string|Error {
if (typeof a === 'number' && typeof b === 'number') {
return a + b;
} else if (typeof a === 'string' && typeof b === 'string') {
return `${a}${b}`;
}
throw new TypeError('Incorrect type to process');
}
}
export default Add;
我有测试文件:add.spec.ts 将测试所有条件。
import sinon from 'sinon';
import { expect } from 'chai';
import Add from '../src/add';
describe('Add', () => {
afterEach(() => {
sinon.restore();
});
it('should process number', () => {
const obj = new Add();
const a = 1;
const b = 2;
// Sinon spy automatically try to apply the last definition known, which is:
// sinon.SinonSpy<[a: string, b: string], string>
// So we need to do type assertions to:
// sinon.SinonSpy<[a: number, b: number], number>
const spy = sinon.spy(obj, 'process') as unknown as sinon.SinonSpy<[a: number, b: number], number>;
const result = obj.process(a, b);
expect(result).to.equal(a + b);
// This line: linter will not complain.
expect(spy.calledOnceWith(a, b)).to.equal(true);
});
it('should process string', () => {
const obj = new Add();
const a = '1';
const b = '2';
// Sinon spy has automatically apply the correct definition.
const spy = sinon.spy(obj, 'process'); // as unknown as sinon.SinonSpy<[a: string, b: string], string>;
const result = obj.process(a, b);
expect(result).to.equal(`${a}${b}`);
// This line: linter will not complain.
expect(spy.calledOnceWith(a, b)).to.equal(true);
});
it('should throw error for invalid type', () => {
const obj = new Add();
const a = 1;
const b = '2';
// Sinon spy automatically try to apply the last definition known, which is:
// sinon.SinonSpy<[a: string, b: string], string>
// So we need to do type assertions to:
// sinon.SinonSpy<[a: any, b: any], Error>
const spy = sinon.spy(obj, 'process') as unknown as sinon.SinonSpy<[a: any, b: any], Error>;
// We also need to cast obj as any, or there will be lint error:
// The call would have succeeded against this implementation,
// but implementation signatures of overloads are not externally visible.
expect(() => (obj as any).process(a, b)).to.throw(TypeError);
// This line: linter will not complain.
expect(spy.calledOnceWith(a, b)).to.equal(true);
});
});
当我在终端使用 ts-mocha 调用 runner 并使用 nyc 进行覆盖时,我得到:(我的编辑也没有抗议)。
$ npx nyc ts-mocha test/add.spec.ts
Add
✓ should process number
✓ should process string
✓ should throw error for invalid type
3 passing (5ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
add.ts | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
参考:https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions