如何在不污染全局命名空间的情况下公开 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 对象以进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章