首页 > 解决方案 > Typescript + Jest:如何部分模拟类实例

问题描述

考虑两个类AB如下所示:

class A {
    private b: B;

    public constructor(b: B){
        this.b=b;
    }

    public doSomething(){
        this.b.myMethod();
    }
}

class B {
    public myMethod(){...}
    public someOtherMethod(){...}
}

我想A在模拟的行为的同时测试类B.myMethod()

目前我们这样做:

const bMock: Partial<B> = {
    myMethod: jest.fn(<some mock here>),
}

const sut = new A(bMock as any);

sut.doSomething();

expect(bMock.myMethod).toBeCalled();

我们想要实现的是类似的结果,但不必通过模拟,as any也不必自己模拟所有方法。检查模拟类型对我们来说非常重要,否则我们将无法通过此测试捕获模拟依赖项中的重大更改。

我们也已经进行了研究sinon,但在某些情况下,我们不希望调用模拟依赖项的构造函数,因此在创建对象后存根对象不是一种选择。存根整个类会导致类似的问题,如上所述。

标签: typescriptjestjs

解决方案


编辑:现在我们正在使用jest-mock-extended以获得更好的笑话兼容性和更多功能

我通过使用Substitute找到了一个不错的解决方案。

唯一的问题是缺少对自述文件中提到的 null/undefined 的检查。不过还是比用好as any

import Substitute, { SubstituteOf } from '@fluffy-spoon/substitute';

class A {
  private b: B;

  public constructor(b: B) {
    this.b = b;
  }

  public doSomething() {
    return this.b.myMethod();
  }
}

class B {
  public myMethod() {
    return 'realMethod';
  }
  public someOtherMethod() {
    return 'realSomeOtherMethod';
  }
}

let bMock: SubstituteOf<B>;
beforeEach(() => {
  bMock = Substitute.for<B>();
});

test('empty mock', () => {
  const sut = new A(bMock);
  console.log(sut.doSomething()); // Output: '[Function]'
});

test('mock myMethod', () => {
  bMock.myMethod().returns('You got mocked!');
  const sut = new A(bMock);
  console.log(sut.doSomething()); // Output:  'You got mocked!'
});

test('does not compile', () => {
  bMock.myMethod().returns(1337); // Will show compilation error due to incompatible type (string vs. number)
  const sut = new A(bMock);
  console.log(sut.doSomething());
});

test('missing null checks', () => {
  bMock.myMethod().returns(); // Will not complain
  const sut = new A(bMock);
  console.log(sut.doSomething()); // Output 'undefined'
});

推荐阅读