码迷,mamicode.com
首页 > Windows程序 > 详细

Sencha Test Futures API 探秘

时间:2016-08-25 21:26:22      阅读:294      评论:0      收藏:0      [点我收藏+]

标签:

原文链接:http://blog.csdn.net/lovelyelfpop/article/details/52301249



英文原文:《Inside the Sencha Test Futures API


编写交互式测试的一个最大的挑战是处理它们的异步特性。Sencha Test 提供了一个新的强大的API,它被设计用来使这些异步测试像同步方式一样简单。

Jasmine 框架的异步测试

测试异步代码并不是什么新鲜事, Jasmine 提供了对其开箱即用的支持, 允许将你的测试标识为异步的:

describe(‘Some tests‘, function () {
    it(‘takes time‘, function (done) { // << "done" marks test async
        doThings().then(done);
    });
});

传递给 it() 的第二个参数是一个函数,这个函数中有名字的那个参数(习惯写为“done”),表明 Jasmine 测试是异步的。即测试(最终)告诉 Jasmine, 它是通过调用提供的“done”来结束的,而不是简单地返回。如果测试在一段时间内没有调用 done 函数(默认5秒), 测试则宣告失败。

这个简单的方法在小测试下没问题, 但是如果有多个步骤, 很难猜得到结束之前要消耗的总时间。服务器请求等在测试环境中甚至是不可预知的, 特别是当环境里可能同时装载到多个浏览器和场景下。

当然, 我们很容易忘记调用 done, 但是通常在写测试的时候就会发现。然而,如果一个测试涉及复杂的逻辑, 很可能就会出现有些分支逻辑调用了 done,而某些分支却没有。

it(‘should eventually call done‘, function (done) {
    if (condition) {  // true 98% of the time
        done();
    } else {
        // oops - fails "randomly"
    }
});

显然,如果可能的话,最好避免写这种分支逻辑。

在交互式测试之前,所有这些问题都是可控的。这种测试不管是在端到端测试应用程序的UI, 还是单元测试应用程序视图和控制器的时候,都是普遍存在的。在这两种情况下, 大多数测试步骤需要异步操作和等待条件, 并混杂着 正确性检查和期望(expectations)。

元素(Element) Futures

为了使交互式测试更具表现力和易于维护, Sencha Test 测试提供了ST.future.* 命名空间下的一套类, 统称为“futures”。

Futures 是在测试代码中创建出来的对象, 它提供了一个简洁的语法来描述异步测试序列。来看一个 Futures 的简单的例子, 下面的代码使用 ST.element() 工厂方法返回的一个 ST.future.Element

it(‘should change text on click‘, function () {
    ST.element(‘button#foo‘).
        click(10, 10).
        textLike(/^Save/).
        and(function (el) {
            expect(el.hasCls(‘somecls‘)).toBe(true);
        });
});

ST.element() 方法接收一个 定位器(locator) (通常是一个字符串,如XPath, 组合查询Component Query, 等等,用于定位一个具体元素). 返回的 ST.future.Element 实例提供了一些方法,我们上面也用到了: click()textLike() 和 and(). 每个方法都返回同样的 ST.future.Element.

要记住, 虽然 futures 看上去是同步调用, 但是它们实际上并没有立即执行相应操作。相反, 它们创建了一个动作序列,只在“当它们能执行”的时候才会执行。

定位器 Locators

测试的第一步使用了 ST.element() 创建一个 future 元素实例。这只是该方法的第一个职能, 第二个同样重要的职能是定位到目标 DOM 元素. 在幕后, ST.element() 保存下了定位器,然后会等待目标元素被添加到 DOM 树中并且可见。

等到测试函数将控制权返回给浏览器,定位元素的任务才会开始.

动作 Actions

测试的第二步是在元素上执行 click() ,可以使用相对于该元素的坐标 (可选) . 当 click() 被调用, 它把点击事件添加到动作序列中. ST.future.Element 提供的很多方法都是动作方法, 并且它们都以相同的方式工作: 后来的动作会排在之前的动作后面, 它们都会在 future 实例所定位到的元素上执行。

动作方法以动词为名称 (比如“click”).

状态 States

测试第三步是 textLike() 函数. 此处安排了一次等待,直到元素的 textContent 匹配给定的正则表达式. 这组方法涉及到描述状态,并注入一次延时操作,直到满足目标状态. 有些状态方法需要轮询检测状态变换,而另外一些可以只监听事件来检测变化。不管怎样,这种细节已经被 Sencha Test 处理了,测试者无需关心.

状态方法的名称是名词或者描述 (比如“collapsed”或者“textLike”).

检查 Inspections

测试的最后一部分是调用 and() 方法. 这个方法安排了一个 函数(function),它会在前一个步骤完成之后,才被调用。此处, 则是在 textContent 满足正则表达式之后。传递给 and() 的函数会接收到2个参数。此处我们只声明了其中一个: 被定位到的 ST.Element

可选的第二个参数是 done 函数, 这和 Jasmine 异步测试一样。如果声明了第二个参数, done 函数就会被传递进去, 而且必须被调用。

这些方法通常用于检查元素, 它的当前状态 和/或 应用程序的其他方面。

自定义等待 Custom Waits

有时需要在代码中写一个等待条件。我们可以修改 and() 方法,使其接收一个 done 函数.

it(‘should change text on click‘, function () {
    ST.element(‘button#foo‘).
        click(10, 10).
        textLike(/^Save/).
        and(function (el, done) {
            // wait for condition and call done()
        });
});

在其他情况下, 测试必须轮询检测适当的状态。Futures 提供了一个 wait() 方法来处理:

it(‘should change text on click‘, function () {
    ST.element(‘button#foo‘).
        click(10, 10).
        textLike(/^Save/).
        wait(function (el) {
            return el.hasCls(‘somecls‘); // return true-like when done
        });
});

总的来说, 最好使用 and() 方式,因为它避免了轮询。不过更多情况下,还是要依赖具体情况做出正确的选择。

组件 Futures

使用 ST.element() 可以很简单地和元素进行异步交互, 不过利用 Sencha Test Futures API 提供的 ST.component() 和 相关类型的 futures 可以做到更多。这些方法创建的类实例,都继承自 ST.future.Component。这些类扩充了 ST.future.Component , 并为其相应类型的组件提供了额外的动作和状态方法。

看个新的测试的例子:

it(‘should change cell text on click‘, function () {
    ST.grid(‘grid#foo‘).
        row(42).
            cell(‘firstName‘).
            reveal().
            click(10, 10).
            textLike(/^Hello$/).
            and(function (cell) {
                expect(cell.el.hasCls(‘somecls‘)).toBe(true);
            });
});

更多定位器 Locators

在这个例子中, 位于 ST.grid() 后面的2个调用是定位方法: row() 和 cell()。有很多方式可以描述目标行和列。这些对应的方法的名字以“row”和“cell”开头。在本例中, 我们使用的方法接收行记录的 id (42) 和 列id(“firstName”)。

一旦我们调用了 row() 方法, 后面的方法链调用则都在此行(row)之上。我们可以通过调用行(row)的 grid() 方法使操作对象回到原来的 grid,如下。

ST.grid(‘grid#foo‘).
    row(42).
        reveal().  // scroll the row into view
        click(10, 10).
    grid().row(999).  // pick a different row
        reveal().
        click(10, 10);

对 列(cell) 来说也是类似的:

ST.grid(‘grid#foo‘).
    row(42).
        cell(‘firstName‘).  // column id
            reveal().  // scroll cell into view
            click(10, 10).
        row().   // return to row 42
        cell(‘lastName‘).
            reveal().
            click(10, 10).
    grid().row(999).
        reveal().
        click(10, 10);

更多动作 Actions

组件 futures 层次结构中的类,为 Ext JS 框架中几个最有用的方法,提供了动作方法。比如, ST.future.Panel 提供了 collapse() 和 expand() 动作方法。这些动作方法为合适的 panel 在正确的时机被调用.

更多状态 States

组件 futures 还提供了额外的 状态方法. 比如, ST.future.Panel 提供了collapsed() 和 expanded() 状态方法,它们会安排一个延时等待 panel 处于目标状态。

继承得到的状态 States

因为ST.future.Component 继承自 ST.future.Element, 所以它继承得到了大部分动作和状态方法. 这种继承会随着 futures 类的层次结构继续下去. 比如, ST.future.ComboBox 继承自 ST.future.TextField , ST.future.TextField 又继承自  ST.future.Field ,  ST.future.Field  又继承自 ST.future.Component.

使用 Jasmine 交互

Sencha Test 与 Jasmine 的集成设计允许 futures 与 Jasmine 传统风格的异步测试协调工作。不过, 在使用 futures 时,通常没有必要使用 Jasmine 的 done 函数,就像上面的例子。

当 future 的一系列操作完成后, 测试就即将完成了, Jasmine 会继续下一个测试。还有, future 序列中的每一步,都可以控制自己的超时时间, 没有必要为整个测试确定一个超时时间。因为每个 future 动作也是5秒超时, 所以通常不必显式地设置一个它。

futures API 的另一个优点是,它利用 and(), 来提供了一种简洁的方式,把异步操作、等待条件和同步检查 混合起来使用。这种做法避免了使用 done 函数, 使测试复杂性降到最低。

避免重复代码 Keeping DRY

Futures 使测试可以遵循 DRY (Don’t Repeat Yourself,避免重复代码) 原则。可以考虑使用下面的方式,而不是在用到的时候才去创建 future 实例.

describe(‘Many tests‘, function () {
    var Page = {
        fooGrid: function () {
            return ST.grid(‘grid#foo‘);
        },
        nameField: function () {
            return ST.textField(‘textfield[name="username"]‘);
        }
    };

    it(‘might take some time‘, function () {
        Page.fooGrid().row(42).
            reveal().
            click(10, 10);
    });

    it(‘might take some more time‘, function () {
        Page.fooGrid().row(999).
            reveal().
            click(10, 10);
    });
});

正如上文所述, 我们只是创建了一个包含一组方法的名为“Page”的对象。这种方法使测试封装了测试对象(即应用程序)的定位器。

如果 page 对象在多个测试中都会有用到, 我们可以把它放在 describe() 块外面, 并给它一个更合适的名称。因为 Sencha Test 在这种场景下会加载所有 JavaScript 文件, page 对象将对所有的测试场景都可用。在不同场景中共享 page 对象, 可以把他们添加到测试项目的 附加库列表(Additional Libraries list) 中。

结论

我们希望本文可以让你对 如何使用 Sencha Test Futures API 来解决异步测试的复杂问题,有个初步了解。请看 API 文档 , 查阅所有已经提供的动作和状态方法, 当然, 还可以寻找更多关于未来版本 Ext JS 组件和特性。祝你测试快乐!




欢迎加入Sencha Touch + Phonegap交流群

1群:194182999 (满)

2群:419834979

共同学习交流(博主QQ:479858761


Sencha Test Futures API 探秘

标签:

原文地址:http://blog.csdn.net/lovelyelfpop/article/details/52301249

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!