Javascript 正在测试的主函数中调用的模拟静态函数

Javascript 正在测试的主函数中调用的模拟静态函数,javascript,typescript,unit-testing,jestjs,mocking,Javascript,Typescript,Unit Testing,Jestjs,Mocking,我想在我正在测试的函数中模拟一些函数 我有一个类,它有几个静态私有函数,从所谓的main函数调用。我想特别测试MyClass.functionad(由mainFunction调用,这是一个私有方法)的结果,因此,我想模拟MyClass.functionA,MyClass.functionB和MyClass.functionC返回默认结果,以便我的测试可以集中在MyClass.FunctionId的结果上 export default class MyClass { static main

我想在我正在测试的函数中模拟一些函数

我有一个类,它有几个静态私有函数,从所谓的
main函数调用。我想特别测试
MyClass.functionad
(由
mainFunction
调用,这是一个私有方法)的结果,因此,我想模拟
MyClass.functionA
MyClass.functionB
MyClass.functionC
返回默认结果,以便我的测试可以集中在
MyClass.FunctionId
的结果上

export default class MyClass {

   static mainFunction(paramA: string, paramB: number): boolean {

        if (MyClass.functionA(paramA, paramB)) {
            return false;
        }

        if (!MyClass.functionB(paramA, paramB)) {
            return false;
        }

        if (MyClass.functionC(paramA, paramB)) {
            return false;
        }

        // I need to focus on the result of this function (i.e. private) for my test
        if (MyClass.functionD(paramA)) {
            return false;
        }

        return true;
   }

}

到目前为止,我已经尝试过jest
spyOn
和一些默认的模拟函数,但我只是迷路了,无法继续,因为我对typescript/Javascript还很陌生。任何与我应该如何继续相关的提示/参考对我来说都足够了。:)谢谢。

TypeScript公用/专用关键字仅适用于TypeScript检查代码的方式-它们对JavaScript输出没有任何影响。因此,您可以通过类似于
MyClass['fucantiona']
的方式访问这些私有方法,这将忽略TSC的类型检查。然后可以使用
jest.spyOn
模拟这些私有方法

以下是我针对您案例的测试策略:

MyClass.ts

export default class MyClass {
  static mainFunction(paramA: string, paramB: number): boolean {
    if (MyClass.fucntionA(paramA, paramB)) {
      return false;
    }

    if (!MyClass.fucntionB(paramA, paramB)) {
      return false;
    }

    if (MyClass.fucntionC(paramA, paramB)) {
      return false;
    }

    if (MyClass.fucntionD(paramA)) {
      return false;
    }

    return true;
  }

  private static fucntionA(a, b) {
    return true;
  }

  private static fucntionB(a, b) {
    return false;
  }

  private static fucntionC(a, b) {
    return true;
  }
  private static fucntionD(a) {
    return false;
  }
}
import MyClass from './MyClass';

describe('65376946', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  });
  it('should pass', () => {
    const fucntionASpy = jest.spyOn(MyClass as any, 'fucntionA').mockReturnValueOnce(false);
    const fucntionBSpy = jest.spyOn(MyClass as any, 'fucntionB').mockReturnValueOnce(true);
    const fucntionCSpy = jest.spyOn(MyClass as any, 'fucntionC').mockReturnValueOnce(false);
    const fucntionDSpy = jest.spyOn(MyClass as any, 'fucntionD').mockReturnValueOnce(true);

    const actual = MyClass.mainFunction('a', 1);
    expect(actual).toBeFalsy();
    expect(fucntionASpy).toBeCalledWith('a', 1);
    expect(fucntionBSpy).toBeCalledWith('a', 1);
    expect(fucntionCSpy).toBeCalledWith('a', 1);
    expect(fucntionDSpy).toBeCalledWith('a');
  });
});
MyClass.test.ts

export default class MyClass {
  static mainFunction(paramA: string, paramB: number): boolean {
    if (MyClass.fucntionA(paramA, paramB)) {
      return false;
    }

    if (!MyClass.fucntionB(paramA, paramB)) {
      return false;
    }

    if (MyClass.fucntionC(paramA, paramB)) {
      return false;
    }

    if (MyClass.fucntionD(paramA)) {
      return false;
    }

    return true;
  }

  private static fucntionA(a, b) {
    return true;
  }

  private static fucntionB(a, b) {
    return false;
  }

  private static fucntionC(a, b) {
    return true;
  }
  private static fucntionD(a) {
    return false;
  }
}
import MyClass from './MyClass';

describe('65376946', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  });
  it('should pass', () => {
    const fucntionASpy = jest.spyOn(MyClass as any, 'fucntionA').mockReturnValueOnce(false);
    const fucntionBSpy = jest.spyOn(MyClass as any, 'fucntionB').mockReturnValueOnce(true);
    const fucntionCSpy = jest.spyOn(MyClass as any, 'fucntionC').mockReturnValueOnce(false);
    const fucntionDSpy = jest.spyOn(MyClass as any, 'fucntionD').mockReturnValueOnce(true);

    const actual = MyClass.mainFunction('a', 1);
    expect(actual).toBeFalsy();
    expect(fucntionASpy).toBeCalledWith('a', 1);
    expect(fucntionBSpy).toBeCalledWith('a', 1);
    expect(fucntionCSpy).toBeCalledWith('a', 1);
    expect(fucntionDSpy).toBeCalledWith('a');
  });
});
单元测试结果:

PASS  examples/65376946/MyClass.test.ts
  65376946
    ✓ should pass (3 ms)

------------|---------|----------|---------|---------|-------------------
File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
------------|---------|----------|---------|---------|-------------------
All files   |   42.86 |       50 |      20 |   42.86 |                   
 MyClass.ts |   42.86 |       50 |      20 |   42.86 | 4,8,12,19-34      
------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        4.168 s

最好将main函数作为一个单元来处理,而不考虑私有方法。这并不总是如此,但如果你不能证明嘲笑是正当的,那么他们可能根本就不应该被嘲笑。太好了!不过我有个问题。您能解释一下使用
一起调用的目的吗?我们是否可以忽略它,因为我们已经将参数传递给main函数,该函数最终将在子函数中使用(在本例中,它们无论如何都是模拟的)?@ihaider断言将使用预期参数调用模拟的函数。换句话说,目的是断言代码执行路径是正确的。每个测试用例应该测试一个代码执行路径