茉莉花测试coffeescript期望(setTimeout).toHaveBeenCalledWith

时间:2012-11-27 19:49:34

标签: tdd coffeescript jasmine

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

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

但我想测试以确保使用正确的args

调用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 ] ]周围的额外方括号有关?还有什么altogther?

我哪里出错?

2 个答案:

答案 0 :(得分:1)

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

进行调试
expect(setTimeout).toHaveBeenCalledWith((-> my_nifty_loop.loop(interval)), interval)

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

并重新运行规范。我想如果额外的方括号消失了,那么你的问题是因为你有两个不同的函数引用。如果它们没有消失,你的LoopObj定义会有一些奇怪的东西,可能是胖箭头操作符(看起来我的n00b眼睛不需要)。

答案 1 :(得分:1)

使用bind辅助功能。

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

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

通过分解这个模式并用setTimeout(与_.delay相同)来组合它,我们可以比较传递给它的参数,因为它们不会被包裹在lambda中。 / p>

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,但你必须记住在每个对象上使用它,并且它不利于带参数的函数。所以我认为以上情况更好。

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