使用 Sinon 存根创建对象作为构造函数的输入

Create Object with Sinon stub as input to constructor

我正在用 TypeScript 中的 mocha、chai 和 sinon 编写单元测试。我需要测试一个 class 构造函数需要一个对象作为输入参数,我想模拟它,因为它太复杂而无法创建。 class 的一些方法也使用该特定输入参数对象的属性。所以我还需要模拟那个模拟对象的方法。

也许一些代码更清楚:

我的 class 看起来像这样(简化):

class Controller {
   constructor(context: Context) {
        this._context = context;
   }
   protected get elasticSearch(): Client {
         return this._context.clients.elasticSearch;
   }

   // the next method should be tested
   public async getSomething(input1: string, input2: string): Promise<ResultObject> {
       const result = new ResultObject();
       await this.elasticSearch.search(query).then((_res)=>{
           // do something with _res
           result.prop = _res;
       });
       return result;
   }
}

现在我想测试getSomething功能。为此,我首先需要创建一个 Controller 对象。但是构造函数需要一个 Context 对象,而我没有。为此,我已经尝试了以下两种方法:

const controllerStub = sinon.createStubInstance(Controller);
controllerStub.elasticSearch = sinon.stub();
--------------------------------------------------
const contextMock = <Context>{};
const controller = new Controller(contextMock);
controller.elasticSearch = sinon.stub();
controller.elasticSearch.search = sinon.stub();

两者都不起作用,因为 属性 elasticSearch 在类型 SinonStubbedInstance<Controller> 上不存在,我无法首先设置 elasticSearch 属性 因为它只有一个 getter.

所以现在我真的不知道要模拟什么以及如何测试 getSomething 函数。在最好的情况下,我想说 elasticsearch.search(query) returns 一个定义的值,这个特定的值应该在 .then 部分进一步处理。我想跳过 elasticSearch 访问,但仍然希望 .then 部分为 运行.

所有关于存根和嵌套存根的文档都没有帮助我。

所以我管理了一个可行的解决方案。这可能不是最佳做法,但这是我能做的最好的做法:

对于 Context 对象,我只是像这样创建一个空对象:

contextMock = <Context><unknown>{
                  clients: {
                      elasticSearch: new Client()
                  }
               }

然后我用它创建控制器对象:

controller = new Controller(contextMock);

然后我可以像这样模拟 elasticSearch 属性 的功能:

searchStub = sinon.stub(contextMock.clients.elasticSearch, 'search');

然后我就拥有了测试 class 所需的所有东西。