为功能代码编写测试?

Writing tests for functional code?

举例来说,假设我们正在构建一个简单的缓存。我们可以采用闭包的函数式方法:

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

比较笼统的问题已经够真实了。但任何封装技术都是如此。不过,我会争辩说,测试或至少单元测试的整个目标是使系统的 public 接口正常工作。因此,如果您没有 public 工具来检查缓存中是否存在某些内容,那么您就不需要对其进行单元测试。

肯定有人不同意,但我觉得这是一个明确的分界线。