Typescript 打字脚本+;Jest:如何部分模拟类实例

Typescript 打字脚本+;Jest:如何部分模拟类实例,typescript,jestjs,Typescript,Jestjs,考虑两类A和B,如下所示: class A { private b: B; public constructor(b: B){ this.b=b; } public doSomething(){ this.b.myMethod(); } } class B { public myMethod(){...} public someOtherMethod(){...} } const bMock: Par

考虑两类
A
B
,如下所示:

class A {
    private b: B;

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

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

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

const sut = new A(bMock as any);

sut.doSomething();

expect(bMock.myMethod).toBeCalled();
我想测试类
A
,同时模拟
B.myMethod()

目前我们这样做:

class A {
    private b: B;

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

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

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

const sut = new A(bMock as any);

sut.doSomething();

expect(bMock.myMethod).toBeCalled();
const bMock:Partial={
myMethod:jest.fn(),
}
const sut=新A(b如有);
sut.doSomething();
expect(bMock.myMethod).toBeCalled();
我们希望得到类似的结果,但不必像任何一样通过模拟,也不必自己模拟所有方法。检查模拟类型对我们来说非常重要,否则我们将无法通过此测试捕获模拟依赖项中的破坏性更改


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

创建泛型如何?(您可以像在示例中一样使用Partial,但在调用它之前,必须检查是否提供了'sut.doSomething'实现

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

class A<T extends B> {
  private b: T;

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

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

const bMock = {myMethod: jest.fn(), someOtherMethod: jest.fn()}
const sut = new A(bMock)
sut.doSomething()
expect(bMock.myMethod).toBeCalled();
B类{
公共myMethod(){}
公共someOtherMethod(){}
}
甲级{
私人b:T;
公共构造函数(b:T){
这个.b=b;
}
公共剂量测定法(){
这个.b.myMethod();
}
}
常量bMock={myMethod:jest.fn(),someOtherMethod:jest.fn()}
const sut=新的A(b锁)
sut.doSomething()
expect(bMock.myMethod).toBeCalled();

我通过使用找到了一个很好的解决方案

唯一的问题是自述文件中提到的空/未定义的检查缺失。尽管如此,仍然比使用任何
更好

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'
});
import Substitute,{SubstituteOf}来自'@flufffy spoon/Substitute';
甲级{
私人b:b;
公共构造函数(b:b){
这个.b=b;
}
公共剂量测定法(){
返回此.b.myMethod();
}
}
B类{
公共方法(){
返回“realMethod”;
}
公共someOtherMethod(){
返回“realsomethermethod”;
}
}
let bMock:替代品f;
在每个之前(()=>{
bMock=替换为();
});
测试('空模拟',()=>{
const sut=新A(b块);
console.log(sut.doSomething());//输出:'[Function]'
});
测试('mock myMethod',()=>{
bMock.myMethod().returns('你被嘲笑了!');
const sut=新A(b块);
console.log(sut.doSomething());//输出:“你被嘲笑了!”
});
测试('不编译',()=>{
bMock.myMethod().returns(1337);//将显示由于不兼容类型(字符串与数字)导致的编译错误
const sut=新A(b块);
console.log(sut.doSomething());
});
测试('缺少空检查',()=>{
bMock.myMethod().returns();//不会抱怨
const sut=新A(b块);
console.log(sut.doSomething());//输出“未定义”
});

可能相关@CharybdeBE上述问题缺乏模拟的部分实现和类型安全性谢谢你的回答。不幸的是,这对我没有帮助。使用泛型
仍然需要
T
来遵循B的整个界面(你的bMock实际上做了什么)。我希望能够通过
bMock
,而不必担心
someOtherMethod()
,也不会丢失类型安全性。因此,基本上是一种替换所有(公共)的方法成员,包括构造函数,使用与其类型相匹配的mock,并且只为特定的单个方法添加mock实现。我明白了。您最好将“a”替换为“Avoid}>,并列出类a在其中使用的所有方法(或者可能提取到单独的接口)但这将重复您在问题中所做的工作,或者您可以将其转换为“any”。第二部分仅显示了在TypeScript中使用Jest安全地模拟类中的单个方法。