4

在学习Jasmine的过程中,遇到了这个问题。我想要一个基本功能运行,然后设置超时再次调用自己......简单的东西。

class @LoopObj
  constructor: ->
  loop: (interval) ->
    #do some stuff
    setTimeout((=>@loop(interval)), interval)

但我想测试以确保使用正确的参数调用 setTimeout

describe "loop", ->
  xit "does nifty things", ->
  it "loops at a given interval", ->
    my_nifty_loop = new LoopObj
    interval = 10
    spyOn(window, "setTimeout")
    my_nifty_loop.loop(interval)
    expect(setTimeout).toHaveBeenCalledWith((-> my_nifty_loop.loop(interval)), interval)

我收到此错误:Expected spy setTimeout to have been called with [ Function, 10 ] but was called with [ [ Function, 10 ] ]

这是因为(-> my_nifty_loop.loop(interval))功能不等于(=>@loop(interval))功能吗?还是它与第二个周围的额外方括号有关[ [ Function, 10 ] ]?还有别的吗?

我哪里出错了?

4

2 回答 2

1

我不太了解 CoffeeScript,但您可以通过替换来调试

expect(setTimeout).toHaveBeenCalledWith((-> my_nifty_loop.loop(interval)), interval)

expect(setTimeout).toHaveBeenCalledWith(jasmine.any(Function), interval)

并重新运行规范。我认为如果多余的方括号消失,那么你的问题是因为你有两个不同的函数引用。如果它们没有消失,那么您的 LoopObj 定义就会有些奇怪,可能是胖箭头运算符(在我的 n00b 眼中看起来没有必要)。

于 2012-11-27T20:18:36.223 回答
1

使用bind辅助函数。

比较 setTimeout 的参数时遇到问题的原因是它隐藏在 lambda 中。您创建的每个 lambda 表达式都是不同的。在这种情况下,lambda 实际上除了将函数绑定到正确的值之外没有添加任何值this

事实证明,这是 JavaScript 中的一种常见模式,Underscore.js 库有一个名为的函数bind正是这样做的。

通过分解此模式并将其与setTimeout(与 相同_.delay)组合,我们可以比较传递给它的参数,因为它们不会被包装在 lambda 中。

window.bindAndDelay = (wait, fn, obj, args...) ->
  setTimeout((-> obj.fn(args...)), wait)

class @LoopObj
  constructor: ->
  loop: (interval) ->
    #do some stuff
    bindAndDelay(interval, @loop, @, interval)

然后在你的测试中:

describe "loop", ->
  xit "does nifty things", ->
  it "loops at a given interval", ->
    my_nifty_loop = new LoopObj
    interval = 10
    spyOn(window, "bindAndDelay")
    my_nifty_loop.loop(interval)
    expect(bindAndDelay).toHaveBeenCalledWith(interval, my_nifty_loop.loop, my_nifty_loop, interval)

我选择将延迟量作为第一个参数,bindAndDelay以便它与应用了任意数量参数的函数一起使用。

另一种方法是使用_.bindAll,但你必须记住在每个对象上都使用它,它不利于带参数的函数。所以我认为上面的更好。

这应该可行,但我仍然认为它很臭。所以如果其他人有更好的答案,请发布!

于 2012-11-27T23:03:07.850 回答