简体   繁体   English

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

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

I feel like this should be really intuitive... but maybe it doesn't work the same way I'm used to thinking of it in Rspec... Here's the function I'm trying to test:我觉得这应该是非常直观的......但也许它的工作方式与我在 Rspec 中习惯的想法不同......这是我正在尝试测试的 function:

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

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

The gist is that mount is a closure variable that ensures that regardless how many times initializePage is called, mountForm is only called once.要点是mount是一个闭包变量,确保无论调用多少次initializePagemountForm只调用一次。

This is my current spec:这是我目前的规格:

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)
        })
      })
    })
  })
})

If I run the specs individually, they pass.如果我单独运行规范,它们就会通过。 Together, and at random, only 1 will pass, the first spec that is run, the second will always fail.一起随机地,只有一个会通过,第一个运行的规范,第二个总是失败。

I know why this is happening... but not the appropriate Jasmine set up to fix this issue.我知道为什么会这样……但不是为解决此问题而设置的适当 Jasmine。

The reason it's happening is because finalSet mounts once across all specs, meaning the closure is set once despite there being two specs.它发生的原因是因为finalSet在所有规范中安装一次,这意味着尽管有两个规范,但闭包设置一次。 So what happens is that if the "first initialization" test runs first, the beforeEach call to finalSet.initializePage() sets the mount = true , this first spec passes, but then, come the "initialize again" test, mount is still true, it doesn't reset, so neither of the 2 beforeEach calls to finalSet.initializePage() will ever call mountForm`, since that happened in the first spec that passed.所以如果"first initialization"测试先运行, beforeEachfinalSet.initializePage()的调用设置mount = true ,第一个规范通过,但是接下来, "initialize again" test, mount is still true, it doesn't reset, so neither of the 2 calls to will ever call mountForm`,因为这发生在第一个通过的规范中。 Hence the second spec fails.因此第二个规范失败了。

On the other hand, if "initialize again" runs first, the stacked 2 beforeEach calls to finalSet.initializePage() work as expected, mountForm is called once, greetCustomer is called twice.另一方面,如果"initialize again"先运行,堆叠的 2 个beforeEach调用finalSet.initializePage()将按预期工作, mountForm被调用一次, greetCustomer被调用两次。 But then when the first "first initialization" spec is called, mount = true already, so nothing gets called.但是当第一个"first initialization"规范被调用时, mount = true已经存在,所以什么都不会被调用。

The immediate question: is there a way to reset the closure as part of the first beforeEach ?直接的问题:有没有办法将闭包重置为第一个beforeEach的一部分?

The larger question: I'm used to this kind of nested speccing from Rspec, but... I'm feeling like maybe this is NOT how one should test in Jasmine, so very open to what a better way of testing this would be is.更大的问题:我已经习惯了 Rspec 中的这种嵌套规范,但是......我觉得也许这不是在 Jasmine 中应该测试的方式,所以非常愿意接受更好的测试方法是。

Thanks!谢谢!

You're trying to test what's essentially a global object across multiple specs.您正在尝试跨多个规范测试本质上是全局 object 的内容。 You'll modify your code in some way to test what you want.您将以某种方式修改您的代码以测试您想要的内容。 Here are some ideas:这里有一些想法:

  1. Add a reset() function to the exported object that sets the mount variable to false, Call this function in a before/afterEach in your specs.将 reset() function 添加到导出的 object 中,将 mount 变量设置为 false,在规范中的 before/afterEach 中调用此 function。 This is similar to how you might reset a database (a global resource) in a Rails spec before every test.这类似于您在每次测试之前如何在 Rails 规范中重置数据库(全局资源)。

  2. Have your code return a function instead of immediately invoking it.让您的代码返回 function 而不是立即调用它。 You might rename the finalSet variable as createFinalSet.您可以将 finalSet 变量重命名为 createFinalSet。 This means you have a finalSet factory instead of a global instance or singleton;这意味着您有一个 finalSet 工厂而不是全局实例或 singleton; each test would have its own finalSet via finalSet = createFinalSet() .每个测试都会通过finalSet = createFinalSet()拥有自己的 finalSet。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM