对具有 DI 依赖项的类开玩笑

lon*_*nix 7 typescript jestjs

各种 Jest 文档展示了“自动”模拟、“手动”模拟或ES6 类模拟(在构造函数中实例化依赖项)的创建。

但是我想使用 DI / IOC 并将依赖项注入到 ctor 中:

// IBar.ts                                           <--- mock this
export default interface IBar {
  /* ...methods... */
}

// Baz.ts                                            <--- mock this
export default class Baz {
  constructor(spam: Spam, ham: IHam) { /* ... */}
  /* ...other methods... */
}

// Foo.ts                                            <--- test this
export default class Foo {
  constructor(bar: IBar, baz: Baz) { /* ... */}
  /* ...other methods... */
}
Run Code Online (Sandbox Code Playgroud)

所以我想在测试中做到这一点:

const barMock = jest.giveMeAMock("../../IBar");  // or jest.giveMeAMock<IBar>();
const bazMock = jest.giveMeAMock("./Baz");       // or jest.giveMeAMock<Baz>();
const foo = new Foo(bar, baz);

expect(foo.something()).toBe(true);
Run Code Online (Sandbox Code Playgroud)

这可以用 Jest 实现吗?

(我在上面使用了一些 TypeScript 语法,但对于 JS/ES6 和 TS 来说也是同样的问题。)

Bri*_*ams 7

当代码转换为 JavaScript 时,TypeScript 接口就会被编译掉......

...但是对于class.

您可以使用自动模拟模块,jest.mockJest在用空模拟函数替换实现时保持模块的 API 表面相同:

baz.js

export default class Baz {
  doSomething() {
    throw new Error('the actual function throws an error');
  }
}
Run Code Online (Sandbox Code Playgroud)

foo.js

export default class Foo {
  constructor(baz) {
    this.baz = baz;
  }
  doSomething() {
    // ...
    this.baz.doSomething();
    // ...
  }
}
Run Code Online (Sandbox Code Playgroud)

代码.test.js

jest.mock('./baz');  // <= auto-mock the module

import Baz from './baz';
import Foo from './foo';

test('Foo', () => {
  const baz = new Baz();  // <= baz is an auto-mocked instance of Baz
  const foo = new Foo(baz);

  foo.doSomething();  // (no error)

  expect(baz.doSomething).toHaveBeenCalled();  // Success!
})
Run Code Online (Sandbox Code Playgroud)