对具有受限制的可观察对象的视图模型进行有用的“红色”和“绿色”测试

时间:2014-03-21 12:01:15

标签: javascript knockout.js qunit

another questionrelevant QUnit documentation的帮助下,我可以创建处理throttled KnockoutJS observables的异步性质的单元测试。

但是,我还没有找到一种优雅的方法让红色和绿色测试在我使用的两个测试跑步者中表现得很好:

  • 基于QUnit浏览器的测试运行器
  • Visual Studio测试运行器(与Chutzpah结合运行JavaScript测试)

假设以下View Model:

var Person = function(firstName, surname) {
    var self = this;

    self.firstName = ko.observable(firstName);
    self.surname = ko.observable(surname);

    self.fullName = ko.computed({
        write: function(val) {
            var parts = val.split(" ");
            self.firstName(parts[0]);
            self.surname(parts[1]);
        },
        read: function() { return self.firstName() + " " + self.surname(); }
    }).extend({throttle: 20});
};

假设这两个基本测试:

test("Can read full name", function(){
    var john = new Person("John", "Doe");
    strictEqual(john.fullName(), "John Doe");
});


test("Can write full name", function(){
    var person = new Person();
    person.fullName("John Doe");
    strictEqual(person.firstName(), "John");
    strictEqual(person.surname(), "Doe");
});

后者will fail。这是有道理的,因为断言立即运行,而fullName调用的实际更新稍后运行:throttle将其延迟20 ms。没有油门things succeed

没问题,从链接问题我了解到我可以使用async test并使用手动订阅再次使事情变为绿色:

asyncTest("Can write full name", function(){
    var person = new Person();

    expect(2);

    person.surname.subscribe(function(val) {
        start();
        strictEqual(person.firstName(), "John");
        strictEqual(person.surname(), "Doe");
    });    

    person.fullName("John Doe");
});

现在,假设我打破了我的View模型:

// self.surname(parts[1]); // "bug" introduced to demonstrate the problem

然后test runner will hang。我可以修理"这个问题是在-say- 2秒后恢复我的测试,不管用什么来结束我的测试:

// After 2 secs we assume the test failed
setTimeout(function() {
    start();
}, 2000);
基于浏览器的测试运行器中的错误代码

This works,但是来自控制台的has an error正确代码:

  

pushFailure()断言在测试上下文之外,是...在QUnit.start

有道理,因为现在start()被调用两次。我的第一个直觉是在setTimeout回调中查看" trancount" (即问我是否需要启动QUnit),但是QUnit不支持这个(可能是因为:D)。

无论如何,要总结所有可能的情况:

  • 绿色因为一切都好。
  • 红色,因为订阅从未被解雇。
  • 红色因为断言失败了。

如何构建测试以便考虑所有情况并且两个测试跑步者都会做出很好的反应?

1 个答案:

答案 0 :(得分:0)

在撰写问题时找到至少一个解决此问题的方法。发布问题以及我的答案(a)以防万一它可以帮助他人和/或(b)其他人可能有更好的解决方案。

底线是在订阅触发后立即清除setTimeout返回值:

asyncTest("Can write full name", function(){
    var person = new Person();

    // After 2 secs we assume the test failed
    var timeout = setTimeout(function() {
        start();
    }, 2000);

    expect(2);

    person.surname.subscribe(function(val) {
        window.clearTimeout(timeout);
        start();
        strictEqual(person.firstName(), "John");
        strictEqual(person.surname(), "Doe");
    });

    person.fullName("John Doe");
});

这适用于所有情况:

两个红色案件都有一个很好的断言失败。

这个解决方案的唯一缺点是它有点冗长,你需要4行额外的测试管道。 (为此目的,也许其他人有一个使用QUnit功能的答案?)

另外,另一个缺点是:如果你增加油门使其高于超时,那么测试首先会变红,但稍后会调整will crash因为start()再次被调用。