定义出一个专门用于处理二维数据的组件,所谓二维数据就是能用二维表格显示出来的数据,所谓处理就是增删改查,很简单。

二、约束

外部程序给该组件传入如下形式的对象,让该组件自行解析。

var testData = {
    metadata: [{name: 'fid', label: 'fid', datatype: 'string', visible: 'false'},
        {name: 'fName', label: '名称', datatype: 'string', visible: 'true'},
        {name: 'fAge', label: '年龄', datatype: 'int', visible: 'true'}],
    data: [{fid: 'id_1', fName: 'yi', fAge: 25},
        {fid: 'id_2', fName: 'anna', fAge: 24},
        {fid: 'id_3', fName: 'kate', fAge: 26}]
};

testData分为metadata和data两部分,两部分均为数组。

metadata内的每一个元素可以对应于表格的一列,持有列标识(键名暂默认为name),列标签,数据类型,是否可见等属性,并不仅限于传入以上属性,外部程序想传入什么就传入什么,组件只管解析和缓存,不管功能。

data内每一个元素的键集合就是所有metadata的列标识,值就是对应的数据。

可以用表格把testData展现为如下外观,其中列明对应于metadata的列标签值(label)

fid 名称 年龄
id_1 yi 25
id_2 anna 24
id_3 kate 26

 

 

 

 

三、实现思路

组件命名为DataModel,仅有一个实例,获取方式为DataModel.getInstance。并提供以下公共方法:

parse: 解析数据

size: 获取数据数量

getData(index, prop): 根据索引和属性获取数据值

getMetadata(key, prop): 根据键和属性获取元数据属性值

foreach(type, fn): 迭代数据或元数据。其中type仅限于'metadata'和'data',迭代过程中会给fn传入迭代对象

update(index, prop, newValue[, callback, url]): 更新数据,返回布尔值。其中callback会在更新成功后调用,url是服务端更新数据地址

addView(view): 添加视图,view必须定义render方法,DataModel更新后(update或parse执行)会触发调用,传入更新信息,通知视图更新

四、单元测试

这里采用TDD的方式,先写测试用例,再写实现。单元测试用例可以在一定程度上减轻手工测试的负担,快速验证基本功能的正确性。并且用例覆盖的场景越全面,质量的有力保障手段,有了它,对代码的修改不再像过去那般战战兢兢了。

1、场景设置

parse
预处理:插入预设数据

size

场景1:获取数据size
getData
场景2:根据索引和属性获取数据值
getMetadata
场景3:根据键和属性获取元数据属性值
foreach
场景4:迭代元数据
场景5:迭代数据
update
场景6:给字符串类型的字段更新数据
场景7:给int类型的字段更新字符串数据
场景8:给int类型的字段更新int数据
场景9:更新一个等于旧值的数据
addView
场景10:更新数据,所有注册于DataModel上的视图都会得到通知

2、qunit测试框架

这是jQuery团队所使用的单元测试框架,轻量级,入门简单,基本用法可以参阅cookbook,这里不作详细介绍。

测试DataModel的代码如下所示:

  1 /**
  2  * 测试DataModel
  3  */
  4  
  5 // 预处理:插入预设数据
  6 var testData = {
  7     metadata: [{name: 'fid', label: 'fid', datatype: 'string', visible: 'false'},
  8         {name: 'fName', label: '名称', datatype: 'string', visible: 'true'},
  9         {name: 'fAge', label: '年龄', datatype: 'int', visible: 'true'}],
 10     data: [{fid: 'id_1', fName: 'yi', fAge: 25},
 11         {fid: 'id_2', fName: 'anna', fAge: 24},
 12         {fid: 'id_3', fName: 'kate', fAge: 26}]
 13 };
 14 
 15 // 获取DataModel实例
 16 var model = DataModel.getInstance();
 17 model.parse(testData);
 18 
 19 // 测试parse效果
 20 // -场景1:获取数据size
 21 test('data size', function(){
 22 var size = model.size();
 23 equal(size, 3, 'get data size');
 24 });
 25 
 26 // -场景2:根据索引和属性获取数据值
 27 test('get data value by index and prop', function(){
 28 var data_1 = model.getData(1, 'fName'),
 29     data_2 = model.getData(2, 'fAge');
 30     strictEqual(data_1, 'anna', 'OK, name is ' + data_1);
 31     strictEqual(data_2, 26, 'OK, age is ' + data_2);
 32 });
 33 
 34 // -场景3:根据键和属性获取元数据属性值
 35 test('get metadata value by key and prop', function(){
 36 var val_1 = model.getMetadata('fid', 'visible'),
 37     val_2 = model.getMetadata('fName', 'label'),
 38     val_3 = model.getMetadata('fAge', 'datatype');
 39     strictEqual(val_1, false, 'OK, visible is ' + val_1);
 40     strictEqual(val_2, '名称', 'OK, label is ' + val_2);
 41     strictEqual(val_3, 'int', 'OK, datatype is ' + val_3);
 42 });
 43 // -测试foreach
 44 test('test foreach', 7, function(){
 45     var i = 0;
 46     // 场景4:迭代元数据
 47     model.foreach('metadata', function(obj){
 48         var result = {name: obj.name, label: obj.label, datatype: obj.datatype, visible: obj.visible};
 49         deepEqual(result, testData.metadata[i], 'for each one metadata testing');
 50         i++;
 51     });
 52     // 场景5:迭代数据
 53     i = 0;
 54     model.foreach('data', function(obj){
 55         deepEqual(obj, testData.data[i], 'for each one data testing');
 56         i++;
 57     });
 58     try{
 59         model.foreach('other', function(obj){
 60             ok(false, "shouldn't be called");
 61         });
 62     }catch(e){
 63         ok(true, 'should reach here');
 64     }
 65 });
 66 
 67 // 写入数据
 68 // -更新数据, 预期断言数是8,更新失败后回调不应该被调用,里面的断言也不会被执行。
 69 test('update data by index, prop and new value', 9, function(){
 70     var newValue = 'yi_2', newValue_int = 30;
 71     // 场景6:给字符串类型的字段更新数据
 72     var result = model.update(0, 'fName', newValue);
 73     strictEqual(result, true, 'update string value success');
 74     // 场景7:给int类型的字段更新字符串数据
 75     result = model.update(1, 'fAge', newValue, function(obj){
 76         ok(false, "callback function shouldn't be called if update failed");
 77     });
 78     strictEqual(result, false, 'OK, update string value into int field failed');
 79     // 更新失败,保留的还是旧值
 80     var data = model.getData(1, 'fAge');
 81     strictEqual(data, 24, 'ok, value is not changed if update failed');
 82     // 场景8:给int类型的字段更新int数据
 83     result = model.update(1, 'fAge', newValue_int, function(obj){
 84         strictEqual(obj.index, 1, 'in calllback obj index is right');
 85         strictEqual(obj.newValue, 30, 'in callback obj newValue is right');
 86         strictEqual(obj.prop, 'fAge', 'in callback obj prop is right');
 87     });
 88     strictEqual(result, true, 'OK, update int value into int field success');
 89     // 更新成功,保留的是新值
 90     data = model.getData(1, 'fAge');
 91     strictEqual(data, 30, 'ok, value is changed if update success');
 92     // 场景9:更新一个等于旧值的数据
 93     result = model.update(1, 'fAge', 30, function(obj){
 94         ok(false, "this shouldn't be called if newValue is equal to oldValue");
 95     });
 96     strictEqual(result, true, "update should return true if old value is equals to new value");
 97     
 98 });
 99 // -更新数据,检验渲染视图
100 test('render data after update data model', 8, function(){
101     // 场景10:更新数据,所有注册于DataModel上的视图都会得到通知
102     var view1 = {render: function(obj){checkRender(obj);}},
103         view2 = {render: function(obj){checkRender(obj);}};
104     model.addView(view1).addView(view2);
105     model.update(1, 'fAge', 28);
106     function checkRender(obj){
107         strictEqual(obj.id, 'id_2', 'check id');
108         strictEqual(obj.index, 1, 'check index');
109         strictEqual(obj.prop, 'fAge', 'check prop');
110         strictEqual(obj.newValue, 28, 'check newValue');
111     }
112 });
View Code

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-01-24
  • 2021-10-01
  • 2021-07-17
  • 2022-12-23
  • 2022-12-23
  • 2021-08-04
猜你喜欢
  • 2022-12-23
  • 2021-12-18
  • 2022-12-23
  • 2021-09-16
  • 2021-09-11
  • 2022-12-23
  • 2021-06-19
相关资源
相似解决方案