当两个方法同名但参数不同时使用sinon.spy

人气:594 发布:2022-10-16 标签: unit-testing mocking typescript sinon spy

问题描述

我尝试在一个对象上使用sinon.spy(),该对象有两个名为Draw的方法(都具有相同的名称,但参数不同),如下所示:

const spy = sinon.spy(obj,'draw')

当我尝试使用expect(spy.calledOnceWith(expectedArgument)).toBeTruthy()测试SPY时,其中expectedArgument匹配DRAW的一个函数定义所给出的类型,我得到一个错误,指出该参数不可分配给DRAW的另一个函数声明所指定的类型。在这种情况下,有没有办法指定我在创建间谍时引用的函数头/声明,以便参数匹配?

推荐答案

是,您需要对SINON间谍进行双重断言,以避免打字错误。由于SINON SPY导致的这个皮棉错误会自动应用已知的最后一个定义。您需要提供将在测试中使用的正确断言。

例如:我在文件add.ts中添加了类。如果两个输入都是数字,则处理方法将尝试将它们相加。如果两个输入都是字符串,则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呼叫跑步者并使用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

995