Jasmine 如何以依赖于闭包变量的任何顺序传递 运行 的规范

Jasmine how pass specs that run in any order that depend on a closure variable

我觉得这应该非常直观...但也许它的工作方式与我在 Rspec 中习惯的想法不同...这是我正在尝试的功能测试:

var finalSet = (function() {
  var mount = false

  return {
    initializePage: function() {
      if (mount == false) {
        this.mountForm();
        mount = true;
      }
      this.greetCustomer();
    },
    greetCustomer: function() {
      ...
    },
    mountForm: function() {
      ...
    }
  }
})();

要点是mount是一个闭包变量,确保无论initializePage被调用多少次,mountForm只被调用一次。

这是我目前的规格:

describe("finalSet", function() {
  describe("initializePage", function() {
    beforeEach(function() {
      spyOn(finalSet, "mountForm")
      spyOn(finalSet, "greetCustomer")
    })
    describe("first initialization", function() {
      beforeEach(function() {
        finalSet.initializePage();
      })
      it("calls both methods", function() {
        expect(finalSet.mountForm).toHaveBeenCalled()
        expect(finalSet.greetCustomer).toHaveBeenCalled()
      })
      describe("initialize again", function() {
        beforeEach(function() {
          finalSet.initializePage();
        })
        it("repeat calls only greetCustomer", function() {
          expect(finalSet.mountForm.calls.count()).toEqual(1)
          expect(finalSet.greetCustomer.calls.count()).toEqual(2)
        })
      })
    })
  })
})

如果我单独 运行 规格,它们就会通过。在一起,随机地,只有一个会通过,第一个规范 运行,第二个总是失败。

我知道为什么会这样……但 Jasmine 设置不合适来解决这个问题。

它发生的原因是因为 finalSet 在所有规范中安装一次,这意味着尽管有两个规范,但闭包设置一次。那么会发生什么情况是,如果 "first initialization" 首先测试 运行,对 finalSet.initializePage()beforeEach 调用设置 mount = true,这第一个规范通过,但是随后,来 "initialize again" test, mountis still true, it doesn't reset, so neither of the 2beforeEachcalls tofinalSet.initializePage()will ever callmountForm`,因为那发生在第一个通过的规范中。因此第二个规范失败了。

另一方面,如果 "initialize again" 运行 首先,对 finalSet.initializePage() 的堆叠 2 beforeEach 调用按预期工作, mountForm 被调用一次,greetCustomer 被调用两次。但是当第一个 "first initialization" 规范被调用时,mount = true 已经被调用了,所以什么也没有被调用。

眼前的问题:有没有办法将闭包重置为第一个 beforeEach 的一部分?

更大的问题:我已经习惯了 Rspec 中的这种嵌套规范,但是......我觉得也许这不是一个人应该在 Jasmine 中测试的方式,所以非常开放更好的测试方法是什么。

谢谢!

您正在尝试跨多个规范测试本质上是全局对象的内容。您将以某种方式修改您的代码以测试您想要的内容。以下是一些想法:

  1. 向导出的对象添加一个 reset() 函数,将 mount 变量设置为 false,在您的规范中的 before/afterEach 中调用此函数。这类似于您在每次测试前在 Rails 规范中重置数据库(全局资源)的方式。

  2. 让您的代码 return 成为一个函数,而不是立即调用它。您可以将 finalSet 变量重命名为 createFinalSet。这意味着你有一个 finalSet 工厂而不是全局实例或单例;每个测试都会通过 finalSet = createFinalSet().

    有自己的 finalSet