Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 模拟实现抛出错误后的Jest spyOn调用计数_Javascript_Unit Testing_Jestjs - Fatal编程技术网

Javascript 模拟实现抛出错误后的Jest spyOn调用计数

Javascript 模拟实现抛出错误后的Jest spyOn调用计数,javascript,unit-testing,jestjs,Javascript,Unit Testing,Jestjs,我有一个程序,可以按此顺序发出三个post请求 http://myservice/login http://myservice/upload http://myservice/logout 代码看起来像这样 async main() { try { await this.login() await this.upload() } catch (e) { throw e } finally { await th

我有一个程序,可以按此顺序发出三个
post
请求

  • http://myservice/login
  • http://myservice/upload
  • http://myservice/logout
  • 代码看起来像这样

    async main() {
        try {
            await this.login()
            await this.upload()
        } catch (e) {
            throw e
        } finally {
            await this.logout()
        }
      }
    
    每个方法在失败时抛出自己的错误

    我使用Jest监视底层请求库(superagent)。对于一个特定的测试,我想测试如果上传函数抛出错误,是否发出注销
    post
    请求

    我通过抛出异常模拟
    post
    请求

    const superagentStub = {
        post: () => superagentStub
    }
    
    const postSpy = jest.spyOn(superagent, 'post')
      .mockImplementationOnce(() => superagentStub)
      .mockImplementationOnce(() => { throw new Error() })
      .mockImplementationOnce(() => superagentStub)
    
    const instance = new ExampleProgram();
    
    expect(async () => await instance.main()).rejects.toThrow(); // This is fine
    expect(postSpy).toHaveBeenNthCalledWith(3, 'http://myservice/logout')
    
    如果我不模拟第三个实现,测试将失败,因为
    logout()
    将抛出自己的
    错误,因为第三个
    post
    请求将作为实时调用失败

    本例中的spy报告只对底层库的
    post
    方法进行了一次调用

  • http://myservice/login
  • 我觉得这很奇怪,因为我期待着给间谍打3个电话

  • http://myservice/login
  • http://myservice/upload ->但它抛出了一个错误
  • http://myservice/logout

  • 请记住如何使用
    expect(…).rejects.toThrow()
    。不过,这有点棘手:

    顺便说一句:在使用JavaScript编码时,让ESLint处于活动状态总是很好的。然后,以下规则可能会警告您错误:(“必须等待或返回异步断言。”)

    解决方案 测试代码最后一行的第二行开头缺少一个
    wait
    。用以下内容替换该行有望解决您的问题:

    wait expect(()=>instance.main()).rejects.toThrow();
    
    这和

    await expect(async()=>await instance.main()).rejects.toThrow();
    
    您声明
    //在您的变体中这很好,但实际上并非如此。你有一个“假阳性”,在那里。Jest很可能也会接受测试的最后一行,即使您否定它,也就是说,如果您将
    .rejects.toThrow()
    替换为
    .rejects.not.toThrow()

    如果在同一个测试套件中有多个测试,Jest可能会声明稍后的某个测试失败,即使它实际上是导致问题的第一个测试

    细节 如果给定行开头没有新的
    wait
    ,则会发生以下情况:

  • expect(…).rejects.toThrow()
    启动
    instance.main()
    -但不等待创建的承诺解决或拒绝
  • instance.main()
    的开头将同步运行到第一个
    wait
    ,即调用
    this.login()
  • 主要是因为对
    superagent.post()
    的模拟是同步的,
    this.login()
    将立即返回。顺便说一句:最好总是用异步模型替换异步函数,例如使用
    .mockResolvedValueOnce()
  • 承诺仍然悬而未决;JavaScript现在运行测试代码的最后一行,Jest声明您的模型只使用过一次(到目前为止)
  • 由于该错误,测试被中止
  • instance.main()
    的调用很可能会在之后继续,导致
    instance.main()
    中出现预期的错误,一个被拒绝的承诺和三次模型使用-但测试失败后所有这些都已失败

  • 是的,确实如此!我们的linter已经启用了
    有效的expect
    ,但是没有
    alwaysAwait
    ,因此感谢您指出,我和其他人都明白了