Templater 对象中的关键方法是 supplant,但是我们并不能从构造器闭包的外部访问到此方法。所以,与 QUnit 类似的测试套件并不能如我们期待的那般工作。另外,我们无法在不尝试调用 .render() 方法,让它作用于模板,查看所生成异常的情况下来验证 defineTemplate 方法的效果。我们当然可以简单地添加一个 getTemplate() 方法,并为了测试而把方法暴露为公有接口,但这并不是一件好的做法。在这个简单示例中这么做可能问题不大,但是在构建复杂对象的时候,如果使用了重要的私有方法,将会导致依赖不可测试的标红代码。这里是上面代码的可测试版本:
  JavaScript
  function Templater() {
  this._templates = {};
  }
  Templater.prototype = {
  _supplant: function(str, params) {
  for (var prop in params) {
  str.split("{" + prop +"}").join(params[prop]);
  }
  return str;
  },
  render: function(name, params) {
  if (typeof this._templates[name] !== "string") {
  throw "Template " + name + " not found!";
  }
  return this._supplant(this._templates[name], params);
  },
  defineTemplate: function(name, template) {
  this._templates[name] = template;
  }
  };
  function Templater() {
  this._templates = {};
  }
  Templater.prototype = {
  _supplant: function(str, params) {
  for (var prop in params) {
  str.split("{" + prop +"}").join(params[prop]);
  }
  return str;
  },
  render: function(name, params) {
  if (typeof this._templates[name] !== "string") {
  throw "Template " + name + " not found!";
  }
  return this._supplant(this._templates[name], params);
  },
  defineTemplate: function(name, template) {
  this._templates[name] = template;
  }
  };
  这里是对应的 QUnit 测试套件:
  JavaScript
  module("Templater");
  test("_supplant", function() {
  var templater = new Templater();
  equal(templater._supplant("{foo}", {foo: "bar"}), "bar"))
  equal(templater._supplant("foo {bar}", {bar: "baz"}), "foo baz"));
  });
  test("defineTemplate", function() {
  var templater = new Templater();
  templater.defineTemplate("foo", "{foo}");
  equal(template._templates.foo, "{foo}");
  });
  test("render", function() {
  var templater = new Templater();
  templater.defineTemplate("hello", "hello {world}!");
  equal(templater.render("hello", {world: "internet"}), "hello internet!");
  });
  module("Templater");
  test("_supplant", function() {
  var templater = new Templater();
  equal(templater._supplant("{foo}", {foo: "bar"}), "bar"))
  equal(templater._supplant("foo {bar}", {bar: "baz"}), "foo baz"));
  });
  test("defineTemplate", function() {
  var templater = new Templater();
  templater.defineTemplate("foo", "{foo}");
  equal(template._templates.foo, "{foo}");
  });
  test("render", function() {
  var templater = new Templater();
  templater.defineTemplate("hello", "hello {world}!");
  equal(templater.render("hello", {world: "internet"}), "hello internet!");
  });
  注意代码中对 render 的测试仅仅是一个确保 defineTemplate 和 supplant 能够互相整合的测试。我们已经单独测试了这些方法,从而让我们可以很容易发现 render 的测试失败是具体哪个组件导致的。
  编写紧密联系的多个函数
  在任何语言中,紧密联系的函数都是重要的,JavaScript 也展示了这么做的原因。你使用 JavaScript 完成的大部分都是由环境提供的全局单例,也是测试套件所依赖的东西。例如,如果你的所有方法都在尝试给 window.location 赋值,那么测试 URL rewriter 会有困难。与此相反,你应当将系统分解成对应的逻辑组件,决定它们如何去做,并编写实际完成的简短函数。你可以使用多个输入输出测试这些函数逻辑,而不测试那个修改 window.location 的终函数。这么做既可以正确地组合系统,也能保证安全。