Node.js 如何验证spied函数的结果(callThrough)

Node.js 如何验证spied函数的结果(callThrough),node.js,typescript,jasmine,nestjs,Node.js,Typescript,Jasmine,Nestjs,我想验证/断言spied函数的结果。我正在与jasmine一起使用nestjs框架。我在我想“监视”的方法上创建了一个jasmine spy,即窃听args和response/exception。但是,我无法访问spied方法的返回值 假设我有一个发射器和监听器,我想断言我的监听器在DB操作失败时抛出一个异常 听众: onModuleInit() { this.emitter.on('documentDeleted', d => this.onDocumentDeleted(d

我想验证/断言spied函数的结果。我正在与jasmine一起使用nestjs框架。我在我想“监视”的方法上创建了一个jasmine spy,即窃听args和response/exception。但是,我无法访问spied方法的返回值

假设我有一个发射器和监听器,我想断言我的监听器在DB操作失败时抛出一个异常

听众:

  onModuleInit() {
    this.emitter.on('documentDeleted', d => this.onDocumentDeleted(d));
  }

  @CatchAndLogAnyException()
  private async onDocumentDeleted(dto: DocumentDeletedEventDTO) {
    this.logger.log(`Deleting document with id '${dto.id}'...`);

    const result = await this.ResearchHearingTestModel.deleteOne({ _id: dto.id });
    if (!result.ok) {
      throw new DataAccessException(
        `Deleting document with id '${dto.id}' failed. Model.deleteOne(id) result: ${result}`,
      );
    }
    if (result.n < 1) {
      throw new DocumentNotFoundException(`Deleting document with id '${dto.id}' failed.`);
    }

    this.logger.log(`Deleted document with id '${dto.id}.`);
  }
因此,在调试时,我可以看到
spyOnDeleted[“[[Scopes]]”][0]。spy.calls.mostRecent[“[[Scopes]]”][0]。calls[0]。returnValue可能是我正在寻找的承诺,但我无法访问或验证它

当我运行测试时,这是输出:

    expect(received).toThrow(expected)

    Expected name: "DocumentNotFoundException"

    Received function did not throw

       95 |       expect(spyDelete).toHaveBeenCalledTimes(1);
       96 |       expect(spyDelete).toHaveBeenCalledWith(expect.objectContaining({ _id: mockId }));
    >  97 |       expect(spyOnDeleted).toThrow(DocumentNotFoundException);
          |                            ^
       98 |     });
       99 |   });
      100 | });

我已经看到了和其他几个类似的问题,但我仍然希望有可能监视callThrough方法并窃听其进出。有什么建议吗?

toThrow
不能用于间谍。您可以使用spies模拟行为,或者使用
callThrough
的实际行为,然后确保使用特定参数调用该方法。但是间谍不会有关于它产生的结果(值或错误)的信息,所以你不能对它设定期望


如果要测试
onDocumentDeleted
的行为,必须通过观察方法的效果来间接测试它。在您的情况下(使用
@CatchAndLogAnyException
),它似乎会写入日志!?因此,您可以监视日志,并期望调用它时显示错误消息。或者,您可以通过公开的方式直接测试该方法。

首先,感谢您的回答。这与我到目前为止所看到的是一致的。但是,我不想在这里用间接效应来检验这种方法。。它可能同时给出假阳性和假阴性。在这种情况下,更改记录器或我的装饰器可能会破坏侦听器的测试。我不喜欢将方法公开的建议,因为我认为这些方法不应该仅仅为了测试而公开。生产代码不应该适应测试,但反过来说,imho。关于
toThrow
toReturn
不捕获间谍方法的输出,我质疑jasmine间谍背后的设计决策。如果间谍不监视他们所依附的方法,他们应该做什么?此外,他们可以更新他们的文档,至少可以反映这一惊人的决定。。我理解你的回答,谢谢你。然而,我仍然在寻找一个与我之前的评论一致的解决方案。我看到了你的冲突,但如果间接测试对你来说不是一个选择,那么你必须以某种方式公开它。测试只能访问公共成员,因为您应该只测试公共接口。只要接口的行为没有改变,就不必改变测试。如果您访问私有方法或属性,则这不成立。当然,在现实中,有时测试公共接口是不可能的。但我看到的唯一选择是将方法(或提取的类)公开,或使用类似于
服务['privateMethod'](params)
的Javascript黑客。我不确定我是否完全同意“不要为测试更改代码”范例。当然,您不应该用测试助手来混乱您的生产代码,否则就不需要这些助手了。但有些代码比其他代码更适合进行单元测试。当您为代码做出设计决策时,将测试牢记在心并不是一个坏主意。TDD的整个概念基于创建可测试代码的思想;这是一种设计模式。再仔细想想,你关于测试私有/公共方法的观点在这里很适用。我不愿意提高这些方法的可见性,因为它们在监听器中,可以是沉默的观察者,隐藏(其方法)并监听事件来触发自身。然而,一旦我决定测试它的行为,我必须以某种方式使直接调用可用于测试,以便隔离地测试它的逻辑。[要么在内部公开,要么将这些方法委托给其他接口。]感谢您消除了对设计模式的误解。