如何在不污染全局命名空间的情况下公开 javascript 对象以进行单元测试

Posted

技术标签:

【中文标题】如何在不污染全局命名空间的情况下公开 javascript 对象以进行单元测试【英文标题】:How to expose javascript objects for unit testing without polluting the global namespace 【发布时间】:2012-01-24 01:46:48 【问题描述】:

我有一个 javascript 自动完成插件,它使用以下类(用 coffeescript 编写):Query、Suggestion、SuggestionCollection 和 Autocomplete。这些类中的每一个都有一个用 Jasmine 编写的相关规范。

插件在模块中定义,例如:

(function()
  // plugin...
).call(this);

这可以防止类污染全局命名空间,但也可以将它们隐藏在任何测试中(使用 jasmine 的规范,或使用 q-unit 之类的单元测试)。

在不污染全局命名空间的情况下公开 javascript 类或对象以进行测试的最佳方法是什么?

我会用我想出的解决方案来回答,但我希望有更标准的东西。

更新:我尝试过的解决方案

因为我是一个

为了规范这些类,我发明了一个名为_test 的全局对象,我公开了其中的所有类以进行测试。例如,在咖啡脚本中:

class Query
  // ...

class Suggestion
  // ...

// Use the classes

// Expose the classes for testing
window._test = 
  Query: Query
  Suggestion: Suggestion

然后,在我的规范中,我可以揭示我正在测试的类:

Query = window._test.Query

describe 'Query', ->
  // ...

这样做的好处是只有_test对象被污染了,不太可能和这个对象的另一个定义发生冲突。不过,它仍然没有我想要的那么干净。我希望有人能提供更好的解决方案。

【问题讨论】:

也许只暴露一些内部变量?示例:window.exposedVars = this(闭包内部)? 我刚刚在您发布此内容几秒钟后添加了我提出的解决方案。是否符合您的建议? 我认为这是一个与“如何在 Java 中测试私有方法”类似的问题。你没有。您只测试相关模块的公共接口,即它导出或以其他方式公开的任何接口。如果您认为需要单独测试大量内部实现,则可以考虑将其作为自己的模块。使用像“require”这样的导入机制,除了模块管理器管理的模块hash,它不需要污染任何东西。 @Thilo 我同意测试公共接口和事件行为是最重要的。不过,对您的内部行为进行测试或规范确实很好。当我早就忘记了为什么我以某种方式实现事物时,一个好的内部类规范将使重构变得更容易。我觉得值得做一些非标准的事情来将功能暴露给测试。另外,我想从上到下做 TDD。 我很好奇是否有人知道一个具有非常好的规范覆盖率的 jQuery 插件示例。我当然希望有更多,基于一些非常糟糕的经验来适应未经测试的插件。 jQuery 社区对其插件的期望更高! 【参考方案1】:

我认为像 CommonJS 模块系统(例如 brunch 使用的)这样的东西会起作用。

您可以将代码分成模块,需要它们的部分将通过require 导入它们。唯一被“污染”的部分是模块管理代码维护的模块映射,与您的test 对象非常相似。

Autocomplete.coffee

class exports.Query
// ...

class exports.Suggestion
// ...

然后在Autocomplete.spec.coffee

Query, Suggestion = require 'app/models/Autocomplete'

describe 'Query', ->

【讨论】:

有趣。我以前没有研究过这个系统。我想这在本质上与我所做的非常相似。但是,对于您想与他人共享的轻量级插件,我不确定是否要投入整个模块管理系统。尽管如此,早午餐页面还是不错的相关读物。

以上是关于如何在不污染全局命名空间的情况下公开 javascript 对象以进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

*防止JS全局污染

防止js全局变量污染方法总结

[转] 防止js全局变量污染方法总结

如何在不指定完整命名空间的情况下使用 OData(7.4) .Net Core 过滤枚举列表?

解决全局变量污染问题

[NodeJS]Node模块原理