【问题标题】:Why my AngularJS async test in Jasmine 1.3.x is not working?为什么我在 Jasmine 1.3.x 中的 AngularJS 异步测试不起作用?
【发布时间】:2017-07-12 13:05:19
【问题描述】:

您好,我有一个使用 AngularJS (1.5.11) 编写的功能完整的网络应用程序,现在我开始使用 karma (0.12.37)、grunt-karma (0.8.3)、karma-chrome 进行单元测试-launcher (0.1.12), karma-phantomjs-launcher (1.0.4), phantomjs-prebuilt (2.1.14), jasmine-promise-matchers (2.3.0) 和 karma-jasmine ( 0.1.6),带有 1.3.x Jasmine 版本。

我对测试异步的东西不是很有信心,所以我开始四处搜索,我总是看到运行 AngularJS 异步测试的唯一强制性内容是在调用异步函数之后的 $rootScope/$scope.$apply/$digest

最终我发现someone suggesting me to use runs() and waitsFor()plunkr 中的测试在使用chrome-launcher 时运行顺利,但在使用phantomjs-launcher 时失败,抛出如下错误:

Expected { myError : { error : 'error_message' }, line : <factory's line of code which throws the error>, sourceURL : 'path/to/factory.js', stack :

     <function throwing error> B@path/to/factory.js:<factory's line of code which throws the error>
     <"async" function> A@path/to/factory.js:<factory's line of code which calls B()>
     path/to/factory-spec.js:<the following line of code: var promise = HandleService.A();>
     invoke@path/to/angular/angular.js:4771:24
     WorkFn@path/to/angular-mocks/angular-mocks.js:3130:26
     execute@path/to/node_modules/karma-jasmine/lib/jasmine.js:1145:22
     next_@path/to/node_modules/karma-jasmine/lib/jasmine.js:2177:38
     start@path/to/node_modules/karma-jasmine/lib/jasmine.js:2130:13
     execute@path/to/node_modules/karma-jasmine/lib/jasmine.js:2458:19
     next_@path/to/node_modules/karma-jasmine/lib/jasmine.js:2177:38
     start@path/to/node_modules/karma-jasmine/lib/jasmine.js:2130:13
     execute@path/to/node_modules/karma-jasmine/lib/jasmine.js:2604:19
     next_@path/to/node_modules/karma-jasmine/lib/jasmine.js:2177:38
     start@path/to/node_modules/karma-jasmine/lib/jasmine.js:2130:13
     execute@path/to/node_modules/karma-jasmine/lib/jasmine.js:2604:19
     next_@path/to/node_modules/karma-jasmine/lib/jasmine.js:2177:38
     onComplete@path/to/node_modules/karma-jasmine/lib/jasmine.js:2173:23
     finish@path/to/node_modules/karma-jasmine/lib/jasmine.js:2561:15
     path/to/node_modules/karma-jasmine/lib/jasmine.js:2605:16

     next_@path/to/node_modules/karma-jasmine/lib/jasmine.js:2187:24
     onComplete@path/to/node_modules/karma-jasmine/lib/jasmine.js:2173:23
     finish@path/to/node_modules/karma-jasmine/lib/jasmine.js:2561:15
     path/to/node_modules/karma-jasmine/lib/jasmine.js:2605:16

     next_@path/to/node_modules/karma-jasmine/lib/jasmine.js:2187:24
     onComplete@path/to/node_modules/karma-jasmine/lib/jasmine.js:2173:23
     finish@path/to/node_modules/karma-jasmine/lib/jasmine.js:2432:15
     path/to/node_modules/karma-jasmine/lib/jasmine.js:2459:16

     next_@path/to/node_modules/karma-jasmine/lib/jasmine.js:2187:24
     path/to/node_modules/karma-jasmine/lib/jasmine.js:2167:23' }, pending : undefined, processScheduled : false } } to be rejected with { myError : { error : 'error_message' } }.

所以我开始认为 Chrome 结果是误报,我需要重写异步测试:因此我尝试了类似 plunkr 的东西,但现在 PhantomJs 和 Chrome 中的测试都失败了,并出现了预期的超时消息:

timeout: timed out after 1500 msec waiting for A should catch an error

注意: 我现在无法将 Jasmine 更新到 2.0 版并使用 done 参数机制,如果我做对了,我什至不应该手动触发$rootScope.$apply/$digest 使用 jasmine-promise-matchers 时。

我怎样才能为这种捕获自定义错误的异步函数和一般的异步函数正确编写异步测试?

【问题讨论】:

  • 离题:不要从过时的测试框架开始。使用茉莉花〜2.6。请不要回复,拿去吧。 Ontopic:我发现您的问题太宽泛/不清楚:我在问题中看不到任何代码(the volatilePlunkr 链接不算在内)。即使是 Plunkr 也不够 mcve。指南:请注意,如果完成,测试运行程序可能无法处理任何expect()ations。你必须use waitsFor() and runs()。测试承诺状态或设置标志
  • Offtopic:... Ontopic:事实是我不知道如何在 plunkr 中设置类似于我的测试环境的东西(这就是为什么我链接了有关所涉及的 grunt 任务的所有信息),但是正如我所说的this gentleman already told me I should use waitsFor() and runs(), I got it,因此我“尽最大努力”提供了一个plunkr。
  • 这位先生错了,对事情的运作方式没有信心。在 AngularJS 测试中你很少需要 done - 更重要的是,runs/waitsFor 这种气味更糟。
  • @estus 有趣,你是在告诉我,好先生,我不会在我的 AngularJS 异步测试中使用 runs() 和 waitsFor() 吗?那么我该如何写我写的那个不会产生误报或任何东西的方式呢?
  • @MichaelRadionov 这里的重点是 $q 承诺本身没有异步行为。它们是同步的(只要它们承诺的代码是同步的),这以及它们与范围摘要的连接确实不同于其他承诺实现。根据我对 Angular 内部结构的了解,$q 和其他内置服务正是这样构建的,目的是让 Jasmine 测试更简洁、更快速。

标签: javascript angularjs unit-testing asynchronous jasmine


【解决方案1】:

Angular 的“异步”测试通常是同步的,因此 waitsForruns 是不必要的,而且显然是有害的。

确实,jasmine-promise-matchers 不需要手动触发摘要来执行 $q 承诺,因为这是在内部完成的。

这里的问题是竞争条件。第一个runs 似乎在$rootScope.$digest() 之后运行,而catch 块永远不会执行 - 第二个runs 也是如此。

相反,它应该被同步测试:

  it('it actually throws an error, yay', function () {
    var promise = HandleService.A();

    expect(promise).toBePromise();
    expect(promise).toBeRejectedWith(jasmine.objectContaining({
      myError: {error: 'error_message'}
    }));
  });

【讨论】:

  • 您的解决方案对我来说听起来很合理,唉,您编写的测试在使用 Chrome 作为测试浏览器时通过(如果它不是误报),而在使用 PhantomJS 时失败,我在我的问题:Expected { myError : { error : 'error_message' }, line : &lt;number_of_line&gt;, sourceURL : 'path/to/factory.js', stack : etc.。你能帮我找出问题所在吗?
  • 很难说。这取决于您正在测试的实际代码是什么。您发布的代码不包含任何会使其失败的内容。通常,您将 Phantom 与 polyfills(core-js 或其他)一起打包,它会按预期工作。如果你没有,那就是你开始的地方。请提供您使用的 Phantom 版本、完整错误(未损坏)以及您的真实代码(如果不同)。
  • 这可能可以用expect(promise).toBeRejectedWith(jasmine.objectContaining({myError: {error: 'error_message'}})), like the documentation shows修复
  • 错误消息显示错误对象有额外的道具,例如如果一个承诺被Error 而不是普通对象拒绝。这可以通过objectContaining部分匹配来处理。
  • 可以有效地忽略 SO 警告。副作用显然是它匹配具有额外道具的对象,这些道具在应用程序逻辑中发挥了一些作用,但没有被考虑在内。一般来说,测试越严格越好。在当前情况下,没有任何警告,除了不清楚发生了什么以及它不是普通对象的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多