Twitter 的工程师文化要求进行测试,许多的测试。在进入 Twitter 之前我还未有过测试 JavaScript 的经验,所以在这之后我学习到了很多。特别是学到了许多过去我使用、书写和鼓励使用的代码其实是不利于书写可测试的代码的。所以我觉得在此分享我所学习到有价值的,如何书写可测试的 JavaScript 几条重要的原则。这里提供的这些示例虽然基于 QUnit,但是也应该适用于其他的 JavaScript 测试框架。
  避免单例
  我受欢迎的博文中的其中一篇是关于如何使用 《JavaScript 模块模式》 在程序中创建强大的单例。这种做法简单有效,但是给测试带来了问题。理由很简单:  单例在测试间造成了状态污染 。与其把单例当作模块使用,不如把他们写成可构造的对象。一旦应用程序初始化,在全局层上分配一个单一的、默认的实例。
  例如,考虑如下的单例模块(当然,是人为的例子):
  JavaScript
  var dataStore = (function() {
  var data = [];
  return {
  push: function (item) {
  data.push(item);
  },
  pop: function() {
  return data.pop();
  },
  length: function() {
  return data.length;
  }
  };
  }());
  var dataStore = (function() {
  var data = [];
  return {
  push: function (item) {
  data.push(item);
  },
  pop: function() {
  return data.pop();
  },
  length: function() {
  return data.length;
  }
  };
  }());
  有了这个模块,我们可能想测试 foo.bar 方法。以下是一个简单的 QUnit 测试套件:
  JavaScript
  module("dataStore");
  test("pop", function() {
  dataStore.push("foo");
  dataStore.push("bar")
  equal(dataStore.pop(), "bar", "popping returns the most-recently pushed item");
  });
  test("length", function() {
  dataStore.push("foo");
  equal(dataStore.length(), 1, "adding 1 item makes the length 1");
  });
  module("dataStore");
  test("pop", function() {
  dataStore.push("foo");
  dataStore.push("bar")
  equal(dataStore.pop(), "bar", "popping returns the most-recently pushed item");
  });
  test("length", function() {
  dataStore.push("foo");
  equal(dataStore.length(), 1, "adding 1 item makes the length 1");
  });