在本系列教程的第一部分,将首先看下系统的整体设计,将完成如下的几个步骤:
设计应用的总体架构;创建一个基本的用户界面模型;使用Jasmine开发框架定义应用的公共接口;开始实现已定义的公共接口。
应用的总体架构
我们打算记事本应用能提供如下功能:创建记事;编辑记事内容;删除记事内容;将记事的内容保存在移动客户端中;查看所有已建立的记事列表。
主界面效果
首先我们要实现的是一个可以增加和编辑记事的界面,我们将这个界面命名为Note Editor。界面看上去应该是如下图的样子(下图是个设计草稿图):
此外,我们需要一个记事的列表的界面,以显示已经存在的记事,这个是我们启功应用程序时首先显示给用户的主界面,主界面如下所示:
接下来,看下如何使用BDD行为驱动的方式进行开发
使用Jasmine Framework框架进行为驱动开发
首先,我们将一步以实例的方式,一边让用户体验什么是行为驱动模式的开发。这种开发模式,能让我们先行定义和测试业务逻辑,可以跟表现层进行分离地设计。先来看下如何使用Jasmine framework这个框架。
Jasmine是一个允许开发者使用行为驱动的方式对Javascript进行测试的框架。这意味着开发者可以使用类似自然语言(易于理解)的方式,通过Jasmine编写测试用例,最后生成Javascript代码,这样明显降低了开发的难度,甚至让不是专业程序员的人也能读懂和编写。
下面快速举一个例子来说明Jasmine框架的使用,更复杂的用法,请参考其官方网站的手册,这个例子希望读者能理解,我们将在教程中稍后会用到。
- describe("Notes functions", function () {
- it("Should return a NoteModel instance", function () {
- var note = Notes.app.createNote();
- expect(note instanceof Notes.model.NoteModel).toBeTruthy();
- });
- });
在这个例子中,我们使用了多种Jasmine框架的特性。其中一个函数方法就是describe(),这个函数用来创建一个包含所有相关的测试的规格说明,我们称之为测试套件。
其中,一个测试规格说明是通过函数方法it()中声明的。当调用it()方法时,要传递一个字符串参数进去,比如这里,我们期待代码能创建并返回一个NoteModel的实例。
接下来,我们通过 var note = Notes.app.createNote();创建了NoteModel的实例,然后使用了expect()函数这个断言(在单元测试中我们称之为断言),这里是断言判断note是否为Notes.model.NoteModel的一个实例,并使用toBeThruthy()这个匹配器去判断这个测试用例是否能正确通过测试。关于匹配器请参考(https://github.com/pivotal/jasmine/wiki/Matchers )。
小结一下,在it()这个函数中,开发者可以编写相关的代码建立测试用例,并可以多次调用expect()方法。
#p#
Jasmine的使用步骤
下面我们开始正式使用Jasmine 框架,首先我们来看下其目录结构。首先我们为项目创建一个名为NoteApp的文件夹。在这个主文件夹下,再创建一个名为app的目录,这个目录中将存放的是程序的应用逻辑和表示层的页面文件。创建一个名为spec的目录,这个目录中存放的是Jasmine的测试套件。除此之外,我们还创建一个lib的目录,这个目录保存的是项目中要用到的一些目录,整个目录架构如下图:
在上图中,读者可能奇怪jqm和jstorage两个文件夹存放的是什么,jqm存放的是jquery mobile的框架文件,而jstorage存放的是jstorage框架的文件,在接下来的学习中将会详细介绍。
接着,我们可以将下载到的jasmine框架的文件解压后,放到jasmine目录下,如下图:
接下来,我们开始编写应用的第一个代码文件,一个是名为app.js,放在app目录下,另外一个是jasmine的测试程序,文件为Appsec.js,文件的保存位置如下图:
最后,我们将编写一个名为specrunner.html的文件,这个文件中将会运行调用jasmine的测试用例。这个文件实际在jasmine的下载包中存在,但我们要对其进行一些必要的修改,以使其引用到恰当的类库文件,代码如下:
- <!-- HEAD -->
- <!-- Jasmine includes -->
- css" rel="stylesheet" type="text/css" />
- <script type="text/javascript"
- src="../lib/jasmine/jasmine-html.js" type="text/javascript">
- </script>
- <!-- Source files -->
- <script src="app/App.js" type="text/javascript"></script>
- <!-- Spec files -->
- <script src="spec/AppSpec.js" type="text/javascript"></script>
- <!-- BODY -->
- <script type="text/javascript">
- jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
- jasmine.getEnv().execute();
- </script>
最后,我们把这个文件放到恰当的位置,如下图:
#p#
开始编写逻辑代码
接下来,我们开始使用jasmine框架以BDD驱动方式编写主要的代码。BDD的方式需要我们不断编写和修改单元测试用例AppSec.js,让我们就从AppSec.js这个文件开始吧。
首先,我们必须断言命名空间是存在的,所以可以在AppSec.js文件中,编写如下代码:
- describe("Public interface exists", function () {
- it("Defines the app", function () {
- expect(Notes.app).toBeDefined();
- });
- });
注意我们在一个名为Public interface exists的测试套件中,编写了测试说明用例。在这个测试套件中,将保存所有对业务逻辑的公共函数测试的用例,这里只是简单去断言应用的命名空间是否已经定义。
接下来我们开始进行测试,使用浏览器中打开specrunner.html这个文件,可以看到如下图的结果:
可以看到,出现了错误的提示:Notes is not defined。这是正确的,因为我们的代码中还没定义命名空间,接下来我们编写代码修正之,如下:
- var NotesNotes = Notes || {}
- Notes.app = (function () {
- return {}
- })();
这里我们定义了应用的命名空间,再次运行jasmine测试框架,结果如下图:
现在我们可以总结出其步骤:先定义出行为,然后为行为编写测试用例,然后运行测试,看测试是否通过,不通过的话就修改代码,再运行测试直到其再次通过,这就是典型的BDD开发方法。
接下来,我们需要将一些记事的内容列表由业务逻辑端返回给前端的表现层,因此我们使用如下的jasmine的行为规格说明去定义,继续往测试套件中增加如下代码:
- describe("Public interface exists", function () {
- it("Should have public interface to return notes list", function () {
- expect(Notes.app.getNotesList).toBeDefined();
- });
- });
这个测试用例断言测试是否已经定义了显示记事列表的方法getNotesList。再编写另外一个测试用例,稍微复杂点的,如下:
- describe("Public interface implementation", function () {
- it("Should return notes list", function () {
- var notesList = Notes.app.getNotesList();
- expect(notesList instanceof Array).toBeTruthy();
- });
- });
这个测试用例,主要用来断言测试返回的记事列表是否是一个数组。 注意我们现
在新建立了一个测试套件,名为 Public interface implementation,在这个测试套件中,专门存
放的是针对接口实现的测试用例。再次在浏览器中运行,可以看到如下图:
可以看到,两个测试用例都出错了,没关系,我们马上编写代码修正:
- Notes.app = (function () {
- var notesList = [];
- function getNotesList() {
- return notesList;
- }
- return {
- getNotesList: getNotesList
- }
- })();
再次运行测试,结果如下图,这次我们通过了测试。
接下来的步骤
接下来,我们将使用jQuery Mobile开始正式开始编写我们的业务逻辑层代码了。请留意本教程系列的第2讲。
原文链接:http://www.byhtml5.com/hjc/2012-01-20/504_7.html
【编辑推荐】