技能树之旅: 从模块分离到测试

在之前说到

奋斗了近半个月后,将fork的代码读懂、重构、升级版本、调整,添加新功能、添加测试、添加CI、添加分享之后,终于almost finish。

今天就来说说是怎样做的。

Github项目组成

以之前造的Lettuce为例,里面有:

  • 代码质量(Code Climate)
  • CI状态(Travis CI)
  • 测试覆盖率(96%)
  • 自动化测试(npm test)
  • 文档

按照Web Developer路线图来说,我们还需要有:

  • 版本管理
  • 自动部署

等等。

Skillock模块化

在SkillTree的源码里,大致分为三部分:

  • namespace函数: 故名思意
  • Calculator也就是TalentTree,主要负责解析、生成url,头像,依赖等等
  • Skill 主要是tips部分。

而这一些都在一个js里,对于一个库来说,是一件好事,但是对于一个项目来说,并非如此。

依赖的库有

  • jQuery
  • Knockout

好在Knockout可以用Require.js进行管理,于是,使用了Require.js进行管理:

 <script type="text/javascript" data-main="app/scripts/main.js" src="app/lib/require.js"></script>

main.js配置如下:

require.config({
  baseUrl: ‘app‘,
  paths:{
    jquery: ‘lib/jquery‘,
    json: ‘lib/json‘,
    text: ‘lib/text‘
  }
});

require([‘scripts/ko-bindings‘]);

require([‘lib/knockout‘, ‘scripts/TalentTree‘, ‘json!data/web.json‘], function(ko, TalentTree, TalentData) {
  ‘use strict‘;
  var vm = new TalentTree(TalentData);
  ko.applyBindings(vm);
});

text、json插件主要是用于处理web.json,即用json来处理技能,于是不同的类到了不同的js文件。

.
|____Book.js
|____Doc.js
|____ko-bindings.js
|____Link.js
|____main.js
|____Skill.js
|____TalentTree.js
|____Utils.js

加上了后来的推荐阅读书籍等等。而Book和Link都是继承自Doc。

define([‘scripts/Doc‘], function(Doc) {
  ‘use strict‘;
  function Book(_e) {
    Doc.apply(this, arguments);
  }
  Book.prototype = new Doc();

  return Book;
});

而这里便是后面对其进行重构的内容。Doc类则是Skillock中类的一个缩影

define([], function() {
  ‘use strict‘;
  var Doc = function (_e) {
    var e = _e || {};
    var self = this;

    self.label = e.label || (e.url || ‘Learn more‘);
    self.url = e.url || ‘javascript:void(0)‘;
  };

  return Doc;
});

或者说这是一个AMD的Class应该有的样子。考虑到this的隐性绑定,作者用了self=this来避免这个问题。最后Return了这个对象,我们在调用的就需要new一个。大部分在代码中返回的都是对象,除了在Utils类里面返回的是函数:

return {
    getSkillsByHash: getSkillsByHash,
    getSkillById: getSkillById,
    prettyJoin: prettyJoin
};

当然函数也是一个对象。

Skillock测试

自动化测试

一直习惯用Travis CI,于是也继续用Travis Ci,.travis.yml配置如下所示:

language: node_js
node_js:
  - "0.10"

notifications:
  email: false

branches:
  only:
    - gh-pages

使用gh-pages的原因是,我们一push代码的时候,就可以自动测试、部署等等,好处一堆堆的。

接着我们需要在package.json里面添加脚本

"scripts": {
    "test": "mocha"
  }

这样当我们push代码的时候便会自动跑所有的测试。因为mocha的主要配置是用mocha.opts,所以我们还需要配置一下mocha.opts

--reporter spec
--ui bdd
--growl
--colors
test/spec

最后的test/spec是指定测试的目录。

Jshint

JSLint定义了一组编码约定,这比ECMA定义的语言更为严格。这些编码约定汲取了多年来的丰富编码经验,并以一条年代久远的编程原则 作为宗旨:能做并不意味着应该做。JSLint会对它认为有的编码实践加标志,另外还会指出哪些是明显的错误,从而促使你养成好的 JavaScript编码习惯。

当我们的js写得不合理的时候,这时测试就无法通过:

line 5   col 25   A constructor name should start with an uppercase letter.
line 21  col 62   Strings must use singlequote.

这是一种驱动写出更规范js的方法。

Mocha

Mocha 是一个优秀的JS测试框架,支持TDD/BDD,结合 should.js/expect/chai/better-assert,能轻松构建各种风格的测试用例。

最后的效果如下所示:

Book,Link
  Book Test
    ? should return book label & url
  Link Test
    ? should return link label & url

测试用例

简单地看一下Book的测试:

/* global describe, it */

var requirejs = require("requirejs");
var assert = require("assert");
var should = require("should");
requirejs.config({
  baseUrl: ‘app/‘,
  nodeRequire: require
});

describe(‘Book,Link‘, function () {
  var Book, Link;
  before(function (done) {
    requirejs([‘scripts/Book‘、], function (Book_Class) {
      Book = Book_Class;
      done();
    });
  });

  describe(‘Book Test‘, function () {
    it(‘should return book label & url‘, function () {
      var book_name = ‘Head First HTML与CSS‘;
      var url = ‘http://www.phodal.com‘;
      var books = {
        label: book_name,
        url: url
      };

      var _book = new Book(books);
      _book.label.should.equal(book_name);
      _book.url.should.equal(url);
    });
  });
});

因为我们用require.js来管理浏览器端,在后台写测试来测试的时候,我们也需要用他来管理我们的依赖,这也就是为什么这个测试这么从的原因,多数情况下一个测试类似于这样子的。(用Jasmine似乎会是一个更好的主意,但是用习惯Jasmine了)

  describe(‘Book Test‘, function () {
    it(‘should return book label & url‘, function () {
      var book_name = ‘Head First HTML与CSS‘;
      var url = ‘http://www.phodal.com‘;
      var books = {
        label: book_name,
        url: url
      };

      var _book = new Book(books);
      _book.label.should.equal(book_name);
      _book.url.should.equal(url);
    });
  });

最后的断言,也算是测试的核心,保证测试是有用的。

结束语(小广告)

在最开始的时候想的是自己写技能树,直至在github上看到https://github.com/352Media/skilltree,就想着基于skilltree做一个,试着翻译了一下,加了点功能。最后没有避免被骂抄袭,最后想想还是自己写一个吧:https://github.com/phodal/sherlock。叫Sherlock的原因是,原来是打算叫shelflock,柯南道尔在书中写道:

人的如同一间空空的阁楼,要有选择地把一些家具装进去。

基于D3.js,可以动态生成Url,而技能树则会基于:https://github.com/phodal/awesome-developer

希望自己看过的书、走过的路可以给大家提供帮助

I’m Phodal.

时间: 2024-11-09 22:44:14

技能树之旅: 从模块分离到测试的相关文章

技能树之旅: 计算点数与从这开始

之前写了一篇技能树之旅: 从模块分离到测试,现在来说说这其中发生了什么. 从这开始 在我们没有点击任何技能的时候,显示的是"从这开始",而当我们点下去时发生了什么? 明显变化如下: 样式变了 URL变成了http://skill.phodal.com/#_a2_1_Name 点数 + 1 点亮了箭头 从Knockout开始 Knockout是一个轻量级的UI类库,通过应用MVVM模式使JavaScript前端UI简单化. 据说有下面的一些特性. 声明式绑定 (Declarative B

使用RazorGenerator实现项目模块分离

一,介绍RazorGenerator的安装方式 1在vs-tool-拓展和更新,找到razor generator并安装 2 以图2-1为例,在建立的Module_X工程中,将对应的cshtml应用zazorgenerator工具(图2-2),结果应如图2-3所示 图2-1 图2-2 图2-3 二,RazorGenerator实现模块分离 在项目建立时,由于项目模块较多,因此就需要将模块分离,各自建立相应工程,然后引用这些dll.然而简单的分离建立工程会出现加载不到视图资源的情况,因此有个想法,

利用python访问Hbase(Thrift模块安装与测试)

hadoop环境介绍: master服务:node1 slave服务器:node2,node3,node4 mysql服务器:node29 Thrift安装在node1服务器上! 相关软件版本: hadoop版本:hadoop-0.20.2 sqoop版本:sqoop-1.2.0-CDH3B4 java版本:jdk1.7.0_67 mysql版本:5.1.65 Thrift版本:thrift-0.9.0 thrift安装链接:http://thrift.apache.org/download/

堡垒机帐号同步模块使用说明和测试手册

麒麟开源堡垒机帐号同步模块用于同步堡垒机到应用发布服务器之间的帐号 1. 相关软件: 如上图所示,一共四个文件,分为两部分,其中: (1)ClientSocket.php和ClientTest.exe,是客户端软件,模拟账号同步命令的发送,用于测试服务.前台调用方式请参考文件ClientSocket.php里的函数: (2)ServicInstall.msi和setup.exe是账号同步软件的安装文件 2. ODBC数据配置: 请确保本地配置好了ODBC源,数据源名称为"audit",

使用TestNG进行模块自动化压力测试

前言 由于最近忙于mirage项目,在分析客户的一个问题时,客户提到了使用TestNG来进行一些压力测试,比如连续拍照500次以上,不断的进入设置.滑动.退出200次. 当时咨询了下项目里的测试同僚,发现我司在压力测试方面做得比较少,性能测试方面主要使用的monkey测试.无奈,只有自己学习琢磨了. 本文一来用于记录学过的东西,二来也可以给会用到这个工具的测试或开发同事借鉴. 通过这个工具,开发同事可以验证自己模块是否存在问题. PS:如果文字有不正确的地方,请务必帮忙纠正. TestNG介绍

Amoeba-mysql主从+读写分离实战+测试+排错

Amoeba-mysql读写分离实战 Amoeba用途有很多,这里看标题我们就先说读写分离,因为我也只会这个.Amoeba定义为国内的,开源的.目前(2015年10月20日)我们用amoeba2.2版本来做. 先说一下本人环境: Mysql 5.6 Centos 6.4 Mysql一主两从已OK. Amoeba 2.2.x Amoeba下载地址:http://sourceforge.net/projects/amoeba/files/Amoeba%20for%20mysql/ 由于Amoeba需

堡垒机-麒麟开源堡垒机帐号同步模块使用说明和测试手册

1. 相关软件: 如上图所示,一共四个文件,分为两部分,其中: (1)ClientSocket.php和ClientTest.exe,是客户端软件,模拟账号同步命令的发送,用于测试服务.前台调用方式请参考文件ClientSocket.php里的函数: (2)ServicInstall.msi和setup.exe是账号同步软件的安装文件 2. ODBC数据配置: 请确保本地配置好了ODBC源,数据源名称为"audit",数据库名为"audit_sec",如果已经配置好

对node.js的net模块的一个测试

抄表系统在接收电表发回的数据的时候,发现有些电表发回的数据没有被socket端口接收到,最后等待时间耗尽,留下了指令超时的记录.因为是在进行虚拟的测试,因此可以根据对服务器发的tcp报文进行分析,分析结果发现在发出抄表指令之后1s之内,虚拟的电表就返回了抄表结果,然后socket服务器没有收到这个记录. 因此做了这个测试,来测试抄表时间和抄表数量对于socket服务器有什么影响. 服务器端: var net = require('net'); var fs = require('fs'); va

Python之旅Day6 模块应用

模块的介绍 模块:简单粗暴的说就是用一砣代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合.而对于一个复杂的功能来,可能需要多个函数才能完成(函数又可以在不同的.py文件中),n个 .py 文件组成的代码集合就称为模块. 如:os 是系统相关的模块:file是文件操作相关的模块 模块分为三种: 1)自定义模块 2)内置标准模块(又称标准库或内置函数) 3)开源模块 time & datetime模块