Javascript 为功能代码编写测试?

Javascript 为功能代码编写测试?,javascript,coffeescript,functional-programming,Javascript,Coffeescript,Functional Programming,举个例子,假设我们正在构建一个简单的缓存。我们可以采用使用闭包的功能性方法: makeCache = -> c = {} (key, fetch) -> if c[key] c[key] else c[key] = fetch() c[key] cache = makeCache() cache(1, -> 1) 我发现这种方法的问题是,您无法轻松测试它。我希望能够检查'1'是否在缓存中。如果我添加更多值,我希望确

举个例子,假设我们正在构建一个简单的缓存。我们可以采用使用闭包的功能性方法:

makeCache = ->
  c = {}
  (key, fetch) ->
    if c[key]
      c[key]
    else
      c[key] = fetch()
      c[key]

cache = makeCache()
cache(1, -> 1)
我发现这种方法的问题是,您无法轻松测试它。我希望能够检查
'1'
是否在缓存中。如果我添加更多值,我希望确保它们也在缓存中

如果我有一个更复杂的缓存,比如LRU缓存,我还想测试其他方面。然而,这些变量完全隐藏在闭包后面

我倾向于使用闭包来想出解决方案,但随后我求助于面向对象的风格,以便其可测试性:

class Cache
  constructor: ->
    @c = {}
  get: (key, fetch) ->
    if c[key]
      c[key]
    else
      c[key] = fetch()
      c[key]

cache = new Cache()
cache.get(1, ->1)
现在我可以访问
cache.c
和我需要检查以测试的任何其他变量


所以我的问题是,当使用函数式闭包时,如何测试代码?

这不会测试您的特定情况吗

cache = new Cache()
cache.get(1, ->1)
expect(cache.get(1, ->0)).toBe(1);
更普遍的问题是真实的。但任何封装技术都是如此。不过,我认为,测试的全部目标,或者至少是单元测试的目标,是使用系统的公共接口。因此,如果您没有公共设施来检查缓存中是否有内容,那么就不需要对其进行单元测试


当然也有人不同意这一点,但我认为这是一条清晰的分界线。

为什么你认为缓存有功能?这似乎是非常必要的:-)顺便说一句,您最好将
fetch
函数传递到
makeCache
并用
键调用它。编写一个测试,测试代码的行为。这不一定需要反省。只需测试同一个键的
fetch
没有被多次调用……如何以更具声明性的方式创建缓存?fetch是一个函数,如果它不在缓存中,它将做一些工作来创建值…声明性的?哦,那很好。我的意思是它不是…所以真正的挑战是当你进入更复杂的东西。就像LRU缓存一样。但我明白你的意思——测试接口而不是内部工作。是的,没错。正如Bergi指出的,通常有一些方法可以根据需要进行更深入的测试。您可以监视
fetch
函数,只需计算调用它的次数。