【问题标题】:Jasmine unit test on Angular $timeout methodAngular $timeout 方法的 Jasmine 单元测试
【发布时间】:2017-02-21 17:46:35
【问题描述】:

我的 Angular 应用程序中有以下控制器。

m = angular.module "myapp.dashboards"

    m.directive "lkDashboardElement", (
      $timeout
      MyAppSettings
    )->

      scope:
        dashboard: "="
        element: "="
        dashboardController: "="
        elementLoaded: "&"

      link: ($scope, $el)->

        if MyAppSettings.shouldCalculateTableWidth

          document.addEventListener "dashboard.element.rendered", =>

            $timeout(->
              ..
              ..
            )

我删除了很多东西,所以只显示了重要的部分。我遇到的问题与我对 Angular $timeout 的使用有关。我目前正在检查某个条件shouldCalculateTableWidth,如果我看到一个事件触发,我会立即超时。

目前我正在尝试编写一个单元测试来检查是否正在使用$timeout

这是我的测试:

describe "in a phantomjs context", ->
  beforeEach ->
    # This sets our Phantom rendering context to true for testing purposes
    MyAppSettings._setIsPhantomRendering(true)

  afterEach ->
    MyAppSettings._setIsPhantomRendering(false)

  it "uses $timeout (instead of applyAsync) for adjusting table widths", ->
    # Creates a dummy dashboard
    dashboardController.queryMap = {1: {view: "foo", model: "bar"}}
    dashboard.elements = [{id: 1}]
    spyOn($timeout, "flush")
    expect($timeout.flush).toHaveBeenCalled()

我要做的只是测试这段代码中是否使用了$timeout,因为当我在 Phantom(图像渲染库)上下文中时,某些图像的渲染方式很重要。当我运行测试时,我收到以下错误:

Expected spy flush to have been called.

我遇到的具体问题是测试中的以下两行:

spyOn($timeout, "flush")
expect($timeout.flush).toHaveBeenCalled()

首先,我不相信我为$timeout 调用了正确的方法。在我的控制器中非常清楚,我打电话给$timeout,而不是$timeout.flush。其次,对于 Jasmine Spys,您不能只使用 spyOn$timeout,因为它需要对类和方法的引用。

所以我不太确定如何继续前进。我将不胜感激 - 谢谢!

【问题讨论】:

  • flush 是一个只存在于ngMock 中的方法,可以从测试中调用。所以监视刷新只检查你是否从测试中调用它。这是你的测试,你知道你做过/没做过,那你为什么要检查它?

标签: javascript angularjs unit-testing jasmine karma-jasmine


【解决方案1】:

在编写单元测试时,必须先调用$timeout.flush(),然后再调用$timeout.verifyNoPendingTasks();

verifyNoPendingTasks() 将在有任何未决超时时抛出异常,所以基本上,您可以断言该异常永远不会像expect(function () {$timeout.verifyNoPendingTasks()}).not.toThrow() 那样抛出。另外,您可以将期望写为expect(function () {$timeout.flush()}).toThrow()

如果在您的控制器中$timeout 有一个固定时间,如$timeout(function() {}, 1000),那么在您的单元测试中,您可以将flush 作为$timeout.flush(1000)

您可以在here阅读更多内容。

此外,您可以查看以下CodePen 的工作示例。

【讨论】:

  • 嘿,谢谢 Gaurav!我需要监视任何东西吗?或者我假设调用$timeout.flush(),然后检查预期?
  • 当您调用$timeout.flush() 时,它会清除所有$timeout(),这意味着在您的测试中,您可以编写类似expect(function() {$timeout.verifyNoPendingTasks()}).not.toThrow() 的断言。
  • 不,你不需要监视任何东西,因为$timeoutngMock 在你的单元测试中提供的一个模拟服务对象。
  • 谢谢 - 我试过了。我在dashboard.elements = ... 之后添加了$timeout.flush(); expect($timeout.verifyNoPendingTasks()).not.toThrow(),但收到以下错误:No more request expected,并且测试退出。这是预期的吗?
  • 上述错误可能是由于 $http 请求队列为空。如果您正在发出任何 http 请求,您可能需要查看 docs.angularjs.org/api/ngMock/service/$httpBackend
【解决方案2】:

如果你想监视 $timeout,你实际上需要在 module.decorator 调用中使用 replace it 进行监视。但是您可能想问问自己,在这种程度上对指令的内部进行微观管理是否真的有意义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-04
    • 1970-01-01
    • 1970-01-01
    • 2017-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多