Sencha Studio 允许开发人员快速和自动测试一个应用程序或 web 页面的细微粒度方面。随着代码库的增长,单元 测试可以确保应用程序的所有部分按照你的预期运行。
本指南, 我们学习生成一个新的应用程序,并设置测试环境, 创建一个可测试的类, 并对它进行单元测试. 所有这些工作都可以在 Sencha Studio 中完成.
如果你有一个已存在的应用程序, 请看测试已有应用程序.
本文假定你已经对 Jasmine 测试框架比较熟悉. 如果你不熟悉 Jasmine 或 测试的概念, 请查阅他们优秀的文档,来获取更多关于编写 Jasmine 测试的信息. 本指南也使用了Sencha Cmd来生成 一个Ext JS应用程序,并假定你已经下载安装它了.
让我们开始吧!
创建一个 Workspace
先打开 Sencha Studio.
你可以在 Sencha Studio 工具栏上点击下面的菜单来生成你需要的 workspace:
Sample CodeSencha Studio -> New -> Workspace...
选择合适的文件路径,然后点击 "OK". 你会发现新生成的 workspace 中有一个测试项目了.
接下来, 我们添加一个应用程序到这个新的 workspace 中.
生成一个 Classic 应用程序
简单起见, 我们生成一个 Classic 应用程序到我们的 workspace 中. 我们也可以用 Sencha Test 来生成应用程序!
点击下面的菜单即可:
Sample CodeSencha Studio -> New -> Application...
接着, 输入应用程序名称, 选择 classic, 然后把 workspace 的位置作为保存论斤. 你的应用程序就会出现在 workspace 下面了.
增加一个可测试的类
这个简单的应用程序只有很少的功能, 所以我们来加点东西用于测试. 此处, 我们创建一个 WindowEditor 类,在MyApp/app/view/main/WindowEditor.js文件里,你可以使用任何 IDE 编写. 你可以使用下面这段代码:
Sample CodeExt.define('MyApp.view.main.WindowEditor', { extend: 'Ext.Window', alias: 'widget.windoweditor', width:400, height:200, padding:20, autoShow: true, title: 'Update Email', items: [{ xtype: 'form', items: [{ xtype: 'textfield', allowBlank: false, vtype: 'email' },{ xtype: 'button', text: 'Submit Change', formBind: true }] }] });
该类继承 window,里面有一个 form, form 里面包含一个文本框和一个按钮. 我们指明了文本框不允许为空而且必须输入一个邮箱地址.
此外, 我们还把按钮的formBind配置为了 true. 这表明,如果表单验证不通过,按钮则一直处于不可用状态. 一旦验证通过, 按钮就可以被点击了.
你还可以把MyApp/app/view/main/MainController.js的onItemSelected函数替换为下面的代码:
Sample CodeonItemSelected: function (sender, record) { Ext.create('MyApp.view.main.WindowEditor'); }
这将为表格打开一个 email editor. 在 Sencha Studio 创建接下来的测试之前,最好不要修改控制器的代码. 也就是说,你会发现,你的应用程序的创建逻辑,和你接下来要写的测试 spec 是平行执行的.
我们最终会使用这个类来测试,当输入的文本满足我们的规定的时候,按钮是否能够成功启用/禁用。
注意:这个 "editor" 此时其实还没啥功能, 不过已经满足我们测试的需要了.
初始化一个测试项目
我们选择 "Applications" 下的 "Tests" 节点,来设置测试项目. 再点击右手边明细页的 "Initialize Test Project". 点击之后, 你会看到一些项目设置. 此时我们还不需要变动它们. 不过, 如果你改了设置, 记得点击 "Save" 才能生效.
下面, 我们来添加一个应用程序场景(scenario).
增加一个场景(Scenario)
一个测试项目必须要有 “场景”, 而后才能添加一套测试 specs.
场景-场景下包含了接下来要创建的测试套件.
要创建一个场景, 点击 Scenarios 标题下面的 "+ Add" 按钮. 然后你可以改变场景的名称和文件路径. 通常, 你会基于你将要测试的内容来命名. 此处, 我们取名 "WindowEditor". 添加完之后, 一定要点击 "Save". 现在我们可以添加一套测试 specs 到场景中了.
增加一个套件(Suite)
现在你可以看到 “WindowEditor” 是 "Tests" 的一个子节点. 点击它, 你会看到一个浏览器列表,还有一个带有 "无测试用例(No tests found)" 字样的面板. 我们来改变它!
我们来添加一个 Jasmine 测试套件.
套件-套件是一个文件,包含了一组 代表应用程序某些方面 的测试. 这些方面可以是一个类,一个组件,或者是一组方法. 具体地,还要取决于你是如何组织你的测试套件的.
"右击" “Window Editor” 节点,然后点击 "New->Jasmine Test Suite". 弹出了一个模态对话框,需要你输入套件名称. 我们取名叫 "WindowValidation" 吧.
添加好之后, 可以看到 "WindowEditor" 底下多了个 "WindowValidation.js" 文件. 点击这个文件,会看到一段默认代码,方便我们开始.
Sample Codedescribe("my test suite", function() { it("should pass", function() { expect(1).toBe(1); }); });
为了便于使用, "右击"WindowValidation.js标签页,点击 "Move Right". 这个操作会将WindowEditor和你的 场景的测试运行器分隔开来. 这样,改动之后,可以很快地测试它们.
目前套件中的代码没什么用处, 我们来给它添加一个 spec.
添加一个 Spec
Spec-指的是一个单独的测试,用一个 JavaScript 函数的形式来解释你的程序应该完成什么. 我们应当用简单的语言来解释测试所期望的结果是什么. 然后提供 javascript 代码执行测试,以达到期望.
需要注意的是,对于创建类和获得对组件的引用来说,多次测试可能会并行应用程序代码的多个方面.
暂时我们先复制下面的代码到你的WindowEditor.js文件,然后点击 "Save":
Sample Codedescribe("formBind true", function() { it("should disable button if email is not valid", function(done) { // Create and reference the WindowEditor and then // get reference to the button and textfield var win = Ext.create('MyApp.view.main.WindowEditor'), button = win.down('button'), field = win.down('textfield'); // Set the field's value to a valid email address // in order to have the button fire an enable event field.setValue('valid@email.com'); button.on('enable', function() { // Set the field's value to an invalid email address (nothing) // in order to have the button fire a disable event field.setValue(''); button.on('disable', function() { // Once the disable event has been called after setting a // bad value, we can safely say that the button is properly // hooked into the form's validity. Thusly, we can // alert the spec to return by calling the done function. done(); }); }); }); });
可以看到, 我们测试了表单是否验证通过会改变按钮的可用状态. 如果文本框的值有效, 表单验证通过, 按钮就可用. 相反的, 如果输入框值无效,表单验证不通过,按钮就不可用. 这种行为是由于按钮的formBind配置被设置为true.
我们可以用过监听按钮的 enable/disable 事件来测试这些条件是否达到. 如果按钮触发了 "enable", 我们就知道表单通过了验证. 如果按钮触发了 "disable" 事件, 那么表单就没有通过验证. 此时, 我们就认为测试成功,然后调用 Jasmine 的done()函数.
很多情况下, 你应该使用一个断言(expectation)来确保结果满足你的要求. 断言使用 expect 函数, 此函数接收一个值, 称作实际值. 然后通过一个接收期望值的 Matcher 函数将2者链接起来. 断言的结果是 true/false, 或者也称作 pass/fail.
也就是说, 这个例子中我们不需要使用断言.done()函数会作为参数传递给it()方法. 当我们决定执行完毕时,我们可以简单调用done()函数. 在处理异步测试时,done()通常作为一个 "成功" 回调. 不过此处, 我们可以用done(),而不需要设置一个断言. 因为在最后的事件中, 我们知道测试已经满足了, 所以不需要断言. 如果最后的事件永远触发不了,done()就不会被调用, 测试就会在5秒后超时, 表示测试失败了.
现在我们有了一个测试用例, 我们来执行它,以确保我们的应用程序编辑器正确实现了表单验证.
执行测试
现在已经连接上了测试, 我们用本地浏览器(local browser)运行一下.
首先, 在 Workspace 导航视图上选择 "WindowEditor" 场景节点,以便显示场景的测试执行标签页. 然后, 在测试执行标签页左侧,根据你的需要选择浏览器. 此处, 我们选择 Chrome.
选择完成后, 你会发现你选择的浏览器正在打开你的应用程序.
注意:如果 "sencha app watch" 正在初始化, 你会在应用程序节点右侧看到一个黄色的眼睛图标. 当图标变成黑色的时候,浏览器才会打开, 表示 "app watch" 初始化完成.
在 WindowEditor 的测试运行器中选择 "WindowValidation.js", 然后点击顶栏的 "Run Selection" . 如果一切正常, 你会得到一个绿色的勾,表示测试执行通过.
再来看看测试失败时发生什么, 我们来改一下测试用例的代码,强制使得测试执行失败.
我们把下面的代码:
// Set the field's value to a valid email address // in order to have the button fire an enable event field.setValue('valid@email.com');
改为:
Sample Codefield.setValue('');
可以想象, 这个改动会使得输入框值无效,按钮的 enable 事件永远不会触发,也就永远不会调用done(). 5 秒之后, 测试超时并执行失败.
保存 spec,然后重新执行一下. 你会看到一个红色的 "1". 表示一个 spec 失败了. 如果你展开 WindowValidation.js, 然后展开formBind true, 你会看到我们的 spec 后边跟着一个红色的 "x". 如果你点击红色的 "x", 你就可以在摘要面板上看到错误的摘要.
结论
可以想象, 本指南只接触了通过 Sencha Studio 使用 Sencha Test 的表面. 希望本文为你提供了基础知识,来探索和发现 Sencha Studio 中更多功能强大的工具。