安装yeoman 选项tbdd和tddbdd怎么选

来自:知乎链接: 已按知乎知识产权要求注明来源作者和链接问题:前端大牛们都学过哪些东西?最近在看bootstrap,发现除了大一的时候看过的html+css,和一些js,JQuery之外,几乎没学什么关于前端的东西。偶尔了解过一些html5。想知道如果作为一个团队的前端负责人还需要学习哪些东西?发现bootstrap与.less有关,除了这个还有哪些是需要学习的?希望得到各方大神的回答。------------补充一下,一些基本的计算机方面的东西还是学习过的。就是说除了最基本的像楼下马前辈说的这些之外,还需要哪些?回答者:张铮铮,http://tychio.net一步一步来。CSS不能编程?用Less、Sass、Stylus、甚至直接用 Absurd,框架除了Bootstrap还有很多。JS写多了很麻烦?jQuery。移动开发?Zepto.js。结构不好?找框架,Backbone.js是MVC,AngularJS和Ember.js是MVVM,Twitter还弄了个事件驱动框架Flight。库多了要优化加载?RequireJS。代码质量成问题?Jasmine、QUnit、Mocha做单元测试。各种浏览器都要测?用Karma。测试通过了部署还有问题?持续集成,用Travis CI。用户行为也要测?用Selenium 。样式测试还有Viff 。觉得JS都够麻烦的?用CoffeeScript。想做动画?Canvas或SVG还有CSS3帮忙,干掉Flash。SVG太难画?用Snap.svg。想开发游戏?用Canvas。自己写FPS太低?用框架,CreateJS.。2D太幼稚?three.js帮你用WebGL开发3D,还不够给力?asm.js让你在浏览器中拥有虚幻3引擎。这一堆东西都要配置部署,麻烦,用Grunt,库太多?用Bower管理,项目开始要创建各种文件文件夹?用Yeoman。开源项目太多了,GitHub.上找,不会?学Git。顺便用Jekyll托管博客,不是吧还有Ruby这玩意...SASS也是Ruby写的,等等Sublime Text是Python写的,要写插件?也学一下。调试太难?用Chrome开发者工具,一堆API和功能。光在电脑浏览器上跑不给力?移动开发HTML5,离开网络就渣了?HTML5离线应用。不如原生应用?用PhoneGap。想调用原生API?开发Firefox OS应用吧。浏览器应用也得会吧,Chrome Firefox都有自己的文档。接着是不是把后端甩了,自己来,装Node.js,所以还得学点服务器知识,想用npm管理node包?linux技巧shell神马的也得学。想前后端通吃?再看看http协议。Web精通了?node-webkit 让你可以写桌面程序了,继续学吧。想学模块化开发?看看CommonJS和AMD规范。理解JS有偏差?看看ECMA-262,等等不知道什么时候第6版就要出了。浏览器各不相同,弄不清该怎么兼容?看看W3C标准,HTML写出来人看的懂,机器读不懂?要SEO,要支持残障人士?看HTML语义化,全会了但IE就是不支持?叫不出名字的浏览器尼玛连JS都不知道是啥?渐进增强。想一次把各种设备全搞定?响应式设计。然后上面这些不过是一些讨巧的小技术。公司做什么业务的?了解一下行业信息。面向大众的产品?交互设计。美工不给力?UI设计。外包和咨询?设计模式、重构方法、算法、数据结构。知道软件工程吗?了解一下敏捷开发,或许还可以试试TDD、ATDD、BDD。看了这么多东西,第一反应是不是求中文文档?学英语去吧。这些也不过是我目前所能看到的一小部分,而且每段基本都是到了一个边界,并不是没得学了,而是继续学又是另一片天地。真心希望有人能帮我填补知识盲区。另外,我仅把一些知识点串起来,不全或不对的地方请见谅。吐槽:知乎的链接功能至少浪费我15分钟时间。回答者:Hoosin,程序员 知乎第99号用户首先我不是大牛1、前端规范,无规不成方圆,养成良好的代码习惯是学习前端开发的基石;2、html+css(html语意化,css要有个人见解,不停留在会写);3、js(研究类库,学习他们的思想,试着编写js库);4、nodeJS,angularJS,“新”是前端的灵魂,要跟着时代走,新技术一定要去了解;5、php+java+Linux+http+db+oc,后端要去了解,说好的全栈工程师呢?可以的话能在mac环境下开发对了,还有git…/* update */刚几个朋友问我为什么要选mac环境:1、Mac OS X 是基于 Unix 的。这一点太重要了,尤其是对开发人员,至少对于我来说很重要,这意味着Unix 下一堆好用的工具都可以随手捡到。如果你是个 windows 开发人员,我想你会在 windows 上装一套cygwin 环境吧?你不用 flex/yacc,grep,screen,ssh,make?好多 open source 的项目只提供cygwin/gcc/make 的编译环境。Mac 就是基于 BSD Unix 的,所有这些都是 built in 的。2、开发环境。c/c++/java/perl/python/php/ruby/lisp,各种 shell,应有尽有,直接支持,非常方便。你要在 windows 上开发 C++,要装个 Visual Studio 编译器吧?或者其他的 C++ 编译器;你要开发 Java,你要下载 Java SDK 吧,说不定还要一个 Elipse 或者 Netbean;你要用 Perl,要安装一个 Perl 解释器吧,Active Perl?你要 python/php/ruby,你要安装……?开发程序需要库,图像处理,视频处理,人工智能之类大部分库都是只支持 Unix/Linux 的。Mac 基于 Unix,所以这些通通都和 Mac 能很好和睦相处。3、编辑器 Vi/Emac。作为 程序员/IT 人员一个好用的编辑器太重要了,因为写程序/改系统配置都需要编辑器。我在Mac上差不多1/2的时间是 browser/email,另外1/2时间差不多就是 Vi 了。4、没有病毒/木马。用了5年多的 Mac 就没看到病毒长成什么样,我还看不到 Mac 上装杀毒软件的需要。5、不需要维护。Mac 买来就直接用,磁盘碎片整理?不需要。装驱动?Mac 装好了,驱动就好了。重装系统?我5年没有重装过一次(期间换了几次不同的 Mac)。6、简洁。Mac 上所有的操作都简洁到了极致,尽量避免干扰用户,增加了程序员的生产力。比如切换无线网功能,在 Mac 上切换只需要1次鼠标点击就可以完成,在 windows 上需要点击多次鼠标(包括一些很愚蠢的确认对话框);再比如卸载 USB 盘,Mac 只需要1次鼠标点击,windows 至少需要点击右下角图标、停止设备、确认对话框等多次点击。7、多窗口切换。这个很方便管理打开的程序/文档。我经常要在多个虚拟窗口切换,比如看浏览网页/邮件一个窗口,写程序/文档一个窗口。8、程序员文化。国外程序员是以 Unix 为主流成长起来的。这一点和国内不同,中国程序员/开发人员大都是从90年代的 DOS 开始的,随着 Windows 的壮大,成长了一批使用 Microsoft 工具的程序员。这也解释了为什么自从 Mac 切换到 Unix 阵营后,Mac 会发展这么快。基于 Unix 的 Mac 一经推出后,迅速赢得了一大批老 Unix hacker 和新 Web 2.0/Linux hacker 的关注,正是因为这些忠实的 fans 影响了他们的人际网络,圈子,博客,从而影响了整个程序员文化。有点像 Ruby on Rails,开始是一小部分人(精英人士)试用,这些人感觉不错就在博客,研讨会等各种场合鼓吹,从而在 Web 开发领域刮起一阵 Ruby 风。9、苹果很酷。每台电脑,每个系列都设计完美,从包装盒,宣传册,广告,电源线,电脑内部,电脑外观,电脑软件都精心设计,风格统一。甚至微小到螺丝,看过苹果机箱上的螺丝,机箱里面的数据线吗?那个也是设计。每个 Mac 上都标记着:Designed by Apple in California,而不是 Desgined in USA,苹果就是这么酷,“我们是一家加州公司”。苹果的保密措施可以说做到了极致,产品官方不发售就在市场上看不到踪影。10、企业家精神。苹果的传奇经历吸引了大批硅谷创业者,Apple/Google/Microsoft/Amazon/eBay/Yahoo 代表了创新,进取的企业家精神。这不是一个大原因,但可以看作是 Mac 在国外,尤其是在美国,尤其是在硅谷,尤其是在大学这么流行的一个小原因吧。据调查2007年美国大学 Mac 市场占有率第一,这些大学精英们毕业以后走上工作岗位,走上社会,再过几年其中一部分走入中层,走进高层,他们会如何影响 Mac 呢?回答者:依华,JS nerd免责申明,偶不是大牛,连小牛都不是 :)纯抛砖引玉,前端,我的理解是主要是HTML, CSS, JavaScript学过哪些东西,我觉得取决于方向,因为JavaScript似乎什么都可以做,一些个人认为的方向,抛砖引玉:1、- 桌面Web前端,也就是通常的前端,jQuery, YUI, MooTools, Dojo, Closure等2、- 移动Web开发 (Mobile Web),jQuery Mobile, Sencha touch (没做过移动开发以前,我错误的认为这个桌面前端差不多,现在觉得差别还是比较大的)3、- Web后端,NodeJS4、- 前后通吃,MeteorJS5、- 单页面Hybrid应用,BackboneJS,AngularJS,EmberJS, KnockoutJS等6、- 移动App开发,PhoneGap, Firefox OS, Titanium7、- 桌面应用,如Window8,再如 rogerwang/node-webkit 路 GitHub8、- 用JavaScript玩转物联网:Technical Machine获100万美元融资,打造Tessel微处理器但无论如何基础都要打扎实了,我觉得回答者:风吹雪,3年前端工作经验HTML,CSS,JAVASCRIPTweb开发万变不离其宗。工具日新月异,但基本功还是这些。不推介在有一定基础之前搞些乱七八糟的工具,什么自动化处理组件。其中的原理自己都没明白,只会是个人云亦云的应声虫。学习前端,少想那些有的没的,少看那些人云亦云的东西。看看大牛的微博,博客。看看他们讨论什么,学习什么。微博上有很多前端大牛。自己稍微看看,就知道了。参与一些开源的项目。慢慢的去积累。想成为任何大牛。你可知道,大牛成长之前都是卑微的苦行者?回答者:Danilo放个图补充@张铮铮的答案:)如果说精通一个领域需要一万小时,HTML+CSS+JS,要三万小时啊回答者:康佳,写字按行收钱授之于鱼不如授之于渔…………………从上向下的学习法是先了解什么是GUI,然后了解前端解决的是什么问题,而这些问题对应的是什么技术,这些技术对应的知识点是什么。从下向上的学习方法是先学习html,js,css的使用,然后学习规范,然后根据遇到的问题寻找解决办法,根据项目积累经验。重点:我厂招前端,我厂有大牛!简历请发jia.来自:知乎链接:/question/推荐IT电商网 (itdianshang)长按指纹→识别图中二维码→添加关注●本文编号1094,以后想阅读这篇文章直接输入1094即可。●本文分类“前端”,搜索分类名可以获得相关文章。●输入m可以获取到全部文章目录●输入r可以获取到热门文章推荐●输入f可以获取到全部分类名称
看过本文的人还看过
人气:37953 更新:
人气:31686 更新:
人气:21769 更新:
人气:20552 更新:
程序猿的更多文章
大家在看 ^+^
推荐阅读 ^o^
5K分辨率210°视场,StarVR要挑战三巨头?
下一站杭州!有酒有肉有大咖,EGO杭州分会成立啦
这只违背乔布斯的触控笔,到底有什么神奇?!
毕业第 4 年就买了法拉利,他有一点人生经验要分享
猜你喜欢 ^_^
24小时热门文章
微信扫一扫
分享到朋友圈君,已阅读到文档的结尾了呢~~
A dissertation submitted to Tongji University in conformity
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
A dissertation submitted to Tongji University in conformity
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer--144.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口specta首页、文档和下载 - TDD/BDD 框架 - 开源中国社区
当前访客身份:游客 [
当前位置:
specta 是一个轻量级的 Objective-C 和 Cocoa 的 TDD/BDD 框架
A light-weight TDD / BDD framework for Objective-C & Cocoa
授权协议:
开发语言:
操作系统:&跨平台&
收录时间:
使用 specta 中的任何问题
共有 202 个类似软件
JUnit是一个Java语言的单元测试框架。它由Kent Beck和Erich Gamma建立,逐渐成为源...
Google Mock 是 Google 刚刚开源的一套 C++ Mock 框架。 Google Mock在google内部超...
继Junit CppUnit的成功后, c语言环境下也出现了开发源码的白盒测试用例CUnit。CUn...
CppTest 是 C++ 的单元测试框架。CppUnit 简单得多,但是效果也不错。下面简要地对...
Google JS Test是一个运行于V8 JavaScript引擎下的Javascript单元测试框架,其在G...
Python单元测试框架(The Python unit testing framework),简称为PyUnit, 是Ken...
CppUTest 是一个功能全面的测试框架。 CppUTest是为了支持在多种操作系统上开发嵌入...
ITEST是面向主要的service接口诸如:HTTP,SOAP,JSON-RPC的轻量级自动化测试框架。...
Peridot 是一个支持 PHP 5.4+ 的高可扩展、用起来很方便的 PHP 测试框架。Peridot...
PowerMock 也是一个单元测试模拟框架,它是在其它单元测试模拟框架的基础上做出的扩...
共有 0 人关注 spectaTDD的iOS开发初步以及Kiwi使用入门
转自OneV's Den的博客 试驱动开发(Test Driven Development,以下简称TDD)是保证代码质量的不二法则,也是先进程序开发的共识。Apple一直致力于在iOS开发中集成更加方便和可用的测试,在Xcode 5中,新的
转自的博客
测试驱动开发(Test Driven Development,以下简称TDD)是保证代码质量的不二法则,也是先进程序开发的共识。
Apple一直致力于在iOS开发中集成更加方便和可用的测试,在Xcode 5中,新的IDE和SDK引入了XCTest来替代原来的SenTestingKit,并且取消了新建工程时的&包括单元测试&的可选项(同样待遇的还有使用ARC的可选项)。新工程将自动包含测试的target,并且相关框架也搭建完毕,可以说测试终于摆脱了iOS开发中&二等公民&的地位,现在已经变得和产品代码一样重要了。
我相信每个工程师在完成自己的业务代码的同时,也有最基本的编写和维护相应的测试代码的义务,以保证自己的代码能够正确运行。更进一步,如果能够使用TDD来进行开发,不仅能保证代码运行的正确性,也有助于代码结构的安排和思考,有助于自身的不断提高。我在最开始进行开发时也曾对测试嗤之以鼻,但后来无数的惨痛教训让我明白那么多工程师痴迷于测试或者追求更完美的测试,是有其深刻含义的。如果您之前还没有开始为您的代码编写测试,我强烈建议,从今天开始,从现在开始(也许做不到的话,也请从下一个项目开始),编写测试,或者尝试一下TDD的开发方式。
而Kiwi是一个iOS平台十分好用的行为驱动开发(Behavior Driven Development,以下简称BDD)的测试框架,有着非常漂亮的语法,可以写出结构性强,非常容易读懂的测试。因为国内现在有关Kiwi的介绍比较少,加上在测试这块很能很多工程师们并没有特别留意,水平层次可能相差会很远,因此在这一系列的两篇博文中,我将从头开始先简单地介绍一些TDD的概念和思想,然后从XCTest的最简单的例子开始,过渡到Kiwi的测试世界。在下一篇中我将继续深入介绍一些Kiwi的其他稍高一些的特性,以期更多的开发者能够接触并使用Kiwi这个优秀的测试框架。
什么是TDD,为什么我们要TDD
测试驱动开发并不是一个很新鲜的概念了。软件开发工程师们(当然包括你我)最开始学习程序编写时,最喜欢干的事情就是编写一段代码,然后运行观察结果是否正确。如果不对就返回代码检查错误,或者是加入断点或者输出跟踪程序并找出错误,然后再次运行查看输出是否与预想一致。如果输出只是控制台的一个简单的数字或者字符那还好,但是如果输出必须在点击一系列按钮之后才能在屏幕上显示出来的东西呢?难道我们就只能一次一次地等待编译部署,启动程序然后操作UI,一直点到我们需要观察的地方么?这种行为无疑是对美好生命和绚丽青春的巨大浪费。于是有一些已经浪费了无数时间的资深工程师们突然发现,原来我们可以在代码中构建出一个类似的场景,然后在代码中调用我们之前想检查的代码,并将运行的结果与我们的设想结果在程序中进行比较,如果一致,则说明了我们的代码没有问题,是按照预期工作的。比如我们想要实现一个加法函数add,输入两个数字,输出它们相加后的结果。那么我们不妨设想我们真的拥有两个数,比如3和5,根据人人会的十以内的加法知识,我们知道答案是8.于是我们在相加后与预测的8进行比较,如果相等,则说明我们的函数实现至少对于这个例子是没有问题的,因此我们对&这个方法能正确工作&这一命题的信心就增加了。这个例子的伪码如下:
&add(float&num1,&float&num&2)&{...}&&&&let&a&=&3;&let&b&=&5;&let&c&=&a&+&b;&&&if&(c&==&8)&{&&&&&&}&else&{&&&&&&}&
&当测试足够全面和具有代表性的时候,我们便可以信心爆棚,拍着胸脯说,这段代码没问题。我们做出某些条件和假设,并以其为条件使用到被测试代码中,并比较预期的结果和实际运行的结果是否相等,这就是软件开发中测试的基本方式。
为什么我们要test
而TDD是一种相对于普通思维的方式来说,比较极端的一种做法。我们一般能想到的是先编写业务代码,也就是上面例子中的add方法,然后为其编写测试代码,用来验证产品方法是不是按照设计工作。而TDD的思想正好与之相反,在TDD的世界中,我们应该首先根据需求或者接口情况编写测试,然后再根据测试来编写业务代码,而这其实是违反传统软件开发中的先验认知的。但是我们可以举一个生活中类似的例子来说明TDD的必要性:有经验的砌砖师傅总是会先拉一条垂线,然后沿着线砌砖,因为有直线的保证,因此可以做到笔直整齐;而新入行的师傅往往二话不说直接开工,然后在一阶段完成后再用直尺垂线之类的工具进行测量和修补。TDD的好处不言自明,因为总是先测试,再编码,所以至少你的所有代码的public部分都应该含有必要的测试。
另外,因为测试代码实际是要使用产品代码的,因此在编写产品代码前你将有一次深入思考和实践如何使用这些代码的机会,这对提高设计和可扩展性有很好的帮助,试想一下你测试都很难写的接口,别人(或者自己)用起来得多纠结。在测试的准绳下,你可以有目的有方向地编码;另外,因为有测试的保护,你可以放心对原有代码进行重构,而不必担心破坏逻辑。这些其实都指向了一个最终的目的:让我们快乐安心高效地工作。
在TDD原则的指导下,我们先编写测试代码。这时因为还没有对应的产品代码,所以测试代码肯定是无法通过的。在大多数测试系统中,我们使用红色来表示错误,因此一个测试的初始状态应该是红色的。接下来我们需要使用最小的代价(最少的代码)来让测试通过。通过的测试将被表示为安全的绿色,于是我们回到了绿色的状态。接下来我们可以添加一些测试例,来验证我们的产品代码的实现是否正确。如果不幸新的测试例让我们回到了红色状态,那我们就可以修改产品代码,使其回到绿色。如此反复直到各种边界和测试都进行完毕,此时我们便可以得到一个具有测试保证,鲁棒性超强的产品代码。在我们之后的开发中,因为你有这些测试的保证,你可以大胆重构这段代码或者与之相关的代码,最后只需要保证项目处于绿灯状态,你就可以保证代码没重构没有出现问题。
简单说来,TDD的基本步骤就是&红&绿&大胆重构&。
使用XCTest来执行TDD
Xcode 5中已经集成了XCTest的测试框架(之前版本是SenTestingKit和OCUnit),所谓测试框架,就是一组让&将测试集成到工程中&以及&编写和实践测试&变得简单的库。我们之后将通过实现一个栈数据结构的例子,来用XCTest初步实践一下TDD开发。在大家对TDD有一些直观认识之后,再转到Kiwi的介绍。如果您已经在使用XCTest或者其他的测试框架了的话,可以直接跳过本节。
首先我们用Xcode新建一个工程吧,选择模板为空项目,在Product Name中输入工程名字VVStack,当然您可以使用自己喜欢的名字。如果您使用过Xcode之前的版本的话,应该有留意到之前在这个界面是可以选择是否使用Unit Test的,但是现在这个选框已经被取消。
新建工程后,可以发现在工程中默认已经有一个叫做VVStackTests的target了,这就是我们测试时使用的target。测试部分的代码默认放到了{ProjectName}Tests的group中,现在这个group下有一个测试文件VVStackTests.m。我们的测试例不需要向别的类暴露接口,因此不需要.h文件。另外一般XCTest的测试文件都会以Tests来做文件名结尾。
Test文件和target
运行测试的快捷键是?U(或者可以使用菜单的Product&Test),我们这时候直接对这个空工程进行测试,Xcode在编译项目后会使用你选择的设备或者模拟器运行测试代码。不出意外的话,这次测试将会失败,如图:
失败的初始测试
VVStackTests.m是Xcode在新建工程时自动为我们添加的测试文件。因为这个文件并不长,所以我们可以将其内容全部抄录如下:
#import&&XCTest/XCTest.h&&&&@interface&VVStackTests&:&XCTestCase&&&@end&&&@implementation&VVStackTests&&&-&(void)setUp&{&&&&&[super&setUp];&&&&&&}&&&-&(void)tearDown&{&&&&&&&&&&[super&tearDown];&}&&&-&(void)testExample&{&&&&&XCTFail(@&No&implementation&for&\&%s\&&,&__PRETTY_FUNCTION__);&}&&&@end&
可以看到,VVStackTests是XCTestCase的子类,而XCTestCase正是XCTest测试框架中的测试用例类。XCTest在进行测试时将会寻找测试target中的所有XCTestCase子类,并运行其中以test开头的所有实例方法。在这里,默认实现的-testExample将被执行,而在这个方法里,Xcode默认写了一个XCTFail的断言,来强制这个测试失败,用以提醒我们测试还没有实现。所谓断言,就是判断输入的条件是否满足。如果不满足,则抛出错误并输出预先规定的字符串作为提示。在这个Fail的断言一定会失败,并提示没有实现该测试。另外,默认还有两个方法-setUp和-tearDown,正如它们的注释里所述,这两个方法会分别在每个测试开始和结束的时候被调用。我们现在正要开始编写我们的测试,所以先将原来的-testExample删除掉。现在再使用?U来进行测试,应该可以顺利通过了(因为我们已经没有任何测试了)。
接下来让我们想想要做什么吧。我们要实现一个简单的栈数据结构,那么当然会有一个类来代表这种数据结构,在这个工程中我打算就叫它VVStack。按照常规,我们可以新建一个Cocoa Touch类,继承NSObject并且开始实现了。但是别忘了,我们现在在TDD,我们需要先写测试!那么首先测试的目标是什么呢?没错,是测试这个VVStack类是否存在,以及是否能够初始化。有了这个目标,我们就可以动手开始编写测试了。在文件开头加上#import &VVStack.h&,然后在VVStackTests.m的@end前面加上如下代码:
-&(void)testStackExist&{&&&&&XCTAssertNotNil([VVStack&class],&@&VVStack&class&should&exist.&);&}&&&-&(void)testStackObjectCanBeCreated&{&&&&&VVStack&*stack&=&[VVStack&new];&&&&&XCTAssertNotNil(stack,&@&VVStack&object&can&be&created.&);&}&
嘛,当然是不可能通过测试的,而且甚至连编译都无法完成,因为我们现在根本没有一个叫做VVStack的类。最简单的让测试通过的方法就是在产品代码中添加VVStack类。新建一个Cocoa Touch的Objective-C class,取名VVStack,作为NSObject的子类。注意在添加的时候,应该只将其加入产品的target中:
添加类的时候注意选择合适的target
由于VVStack是NSObject的子类,所以上面的两个断言应该都能通过。这时候再运行测试,成功变绿。接下来我们开始考虑这个类的功能:栈的话肯定需要能够push,并且push后的栈顶元素应该就是刚才所push进去的元素。那么建立一个push方法的测试吧,在刚才添加的代码之下继续写:
-&(void)testPushANumberAndGetIt&{&&&&&VVStack&*stack&=&[VVStack&new];&&&&&[stack&push:2.3];&&&&&double&topNumber&=&[stack&top];&&&&&XCTAssertEqual(topNumber,&2.3,&@&VVStack&should&can&be&pushed&and&has&that&top&value.&);&}&
因为我们还没有实现-push:和-top方法,所以测试毫无疑问地失败了(在ARC环境中直接无法编译)。为了使测试立即通过我们首先需要在VVStack.h中声明这两个方法,然后在.m的实现文件中进行实现。令测试通过的最简单的实现是一个空的push方法以及直接返回2.3这个数:
&@interface&VVStack&:&NSObject&-&(void)push:(double)&-&(double)&@end&&&&@implementation&VVStack&-&(void)push:(double)num&{&&&}&&&-&(double)top&{&&&&&return&2.3;&}&@end&
再次运行测试,我们顺利回到了绿灯状态。也许你很快就会说,这算哪门子实现啊,如果再增加一组测试例,比如push一个4.6,然后检查top,不就失败了么?我们难道不应该直接实现一个真正的合理的实现么?对此的回答是,在实际开发中,我们肯定不会以这样的步伐来处理像例子中这样类似的简单问题,而是会直接跳过一些error-try的步骤,实现一个比较完整的方案。但是在更多的时候,我们所关心和需要实现的目标并不是这样容易。特别是在对TDD还不熟悉的时候,我们有必要放慢节奏和动作,将整个开发理念进行充分实践,这样才有可能在之后更复杂的案例中正确使用。于是我们发扬不怕繁杂,精益求精的精神,在刚才的测试例上增加一个测试,回到VVStackTests.m中,在刚才的测试方法中加上:
-&(void)testPushANumberAndGetIt&{&&&&&&&&&&[stack&push:4.6];&&&&&topNumber&=&[stack&top];&&&&&XCTAssertEqual(topNumber,&4.6,&@&Top&value&of&VVStack&should&be&the&last&num&pushed&into&it&);&}&
很好,这下子我们回到了红灯状态,这正是我们所期望的,现在是时候来考虑实现这个栈了。这个实现过于简单,也有非常多的思路,其中一种是使用一个NSMutableArray来存储数据,然后在top方法里返回最后加入的数据。修改VVStack.m,加入数组,更改实现:
&@interface&VVStack()&@property&(nonatomic,&strong)&NSMutableArray&*&@end&&&@implementation&VVStack&-&(id)init&{&&&&&if&(self&=&[super&init])&{&&&&&&&&&_numbers&=&[NSMutableArray&new];&&&&&}&&&&&return&&}&&&-&(void)push:(double)num&{&&&&&[self.numbers&addObject:@(num)];&}&&&-&(double)top&{&&&&&return&[[self.numbers&lastObject]&doubleValue];&}&@end&
测试通过,注意到在-testStackObjectCanBeCreated和testPushANumberAndGetIt两个测试中都生成了一个VVStack对象。在这个测试文件中基本每个测试都会需要初始化对象,因此我们可以考虑在测试文件中添加一个VVStack的实例成员,并将测试中的初始化代码移到-setUp中,并在-tearDown中释放。
接下来我们可以模仿继续实现pop等栈的方法。鉴于篇幅这里不再继续详细实现,大家可以自己动手试试看。记住先实现测试,然后再实现产品代码。一开始您可能会觉得这很无聊,效率低下,但是请记住这是起步练习不可缺少的一部分,而且在我们的例子中其实一切都是以&慢动作&在进行的。相信在经过实践和使用后,您将会逐渐掌握自己的节奏和重点测试。关于使用XCTest到这里为止的代码,可以在github上找到。
Kiwi和BDD的测试思想
XCTest是基于OCUnit的传统测试框架,在书写性和可读性上都不太好。在测试用例太多的时候,由于各个测试方法是割裂的,想在某个很长的测试文件中找到特定的某个测试并搞明白这个测试是在做什么并不是很容易的事情。所有的测试都是由断言完成的,而很多时候断言的意义并不是特别的明确,对于项目交付或者新的开发人员加入时,往往要花上很大成本来进行理解或者转换。另外,每一个测试的描述都被写在断言之后,夹杂在代码之中,难以寻找。使用XCTest测试另外一个问题是难以进行mock或者stub,而这在测试中是非常重要的一部分(关于mock测试的问题,我会在下一篇中继续深入)。
行为驱动开发(BDD)正是为了解决上述问题而生的,作为第二代敏捷方法,BDD提倡的是通过将测试语句转换为类似自然语言的描述,开发人员可以使用更符合大众语言的习惯来书写测试,这样不论在项目交接/交付,或者之后自己修改时,都可以顺利很多。如果说作为开发者的我们日常工作是写代码,那么BDD其实就是在讲故事。一个典型的BDD的测试用例包活完整的三段式上下文,测试大多可以翻译为Given..When..Then的格式,读起来轻松惬意。BDD在其他语言中也已经有一些框架,包括最早的Java的JBehave和赫赫有名的Ruby的RSpec和Cucumber。而在objc社区中BDD框架也正在欣欣向荣地发展,得益于objc的语法本来就非常接近自然语言,再加上C语言宏的威力,我们是有可能写出漂亮优美的测试的。在objc中,现在比较流行的BDD框架有cedar,specta和Kiwi。其中个人比较喜欢Kiwi,使用Kiwi写出的测试看起来大概会是这个样子的:
describe(@&Team&,&^{&&&&&context(@&when&newly&created&,&^{&&&&&&&&&it(@&should&have&a&name&,&^{&&&&&&&&&&&&&id&team&=&[Team&team];&&&&&&&&&&&&&[[team.name&should]&equal:@&Black&Hawks&];&&&&&&&&&});&&&&&&&&&&&it(@&should&have&11&players&,&^{&&&&&&&&&&&&&id&team&=&[Team&team];&&&&&&&&&&&&&[[[team&should]&have:11]&players];&&&&&&&&&});&&&&&});&});&
我们很容易根据上下文将其提取为Given..When..Then的三段式自然语言
Given a team, when newly created, it should have a name, and should have 11 players
很简单啊有木有!在这样的语法下,是不是写测试的兴趣都被激发出来了呢。关于Kiwi的进一步语法和使用,我们稍后详细展开。首先来看看如何在项目中添加Kiwi框架吧。
在项目中添加Kiwi
最简单和最推荐的方法当然是CocoaPods,如果您对CocoaPods还比较陌生的话,推荐您花时间先看一看这篇CocoaPods的简介。Xcode 5和XCTest环境下,我们需要在Podfile中添加类似下面的条目(记得将VVStackTests换成您自己的项目的测试target的名字):
target&:VVStackTests,&:exclusive&=&&true&do&&&&pod&'Kiwi/XCTest'&end&
之后pod install以后,打开生成的xcworkspace文件,Kiwi就已经处于可用状态了。另外,为了我们在新建测试的时候能省点事儿,可以在官方repo里下载并运行安装Kiwi的Xcode Template。如果您坚持不用CocoaPods,而想要自己进行配置Kiwi的话,可以参考这篇wiki。
行为描述(Specs)和期望(Expectations),Kiwi测试的基本结构
我们先来新建一个Kiwi测试吧。如果安装了Kiwi的Template的话,在新建文件中选择Kiwi/Kiwi Spec来建立一个Specs,取名为SimpleString,注意选择目标target为我们的测试target,模板将会在新建的文件名字后面加上Spec后缀。传统测试的文件名一般以Tests为后缀,表示这个文件中含有一组测试,而在Kiwi中,一个测试文件所包含的是一组对于行为的描述(Spec),因此习惯上使用需要测试的目标类来作为名字,并以Spec作为文件名后缀。在Xcode 5中建立测试时已经不会同时创建.h文件了,但是现在的模板中包含有对同名.h的引用,可以在创建后将其删去。如果您没有安装Kiwi的Template的话,可以直接创建一个普通的Objective-C test case class,然后将内容替换为下面这样:
#import&&Kiwi/Kiwi.h&&&SPEC_BEGIN(SimpleStringSpec)&&describe(@&SimpleString&,&^{&&});&&SPEC_END&
你可能会觉得这不是objc代码,甚至怀疑这些语法是否能够编译通过。其实SPEC_BEGIN和SPEC_END都是宏,它们定义了一个KWSpec的子类,并将其中的内容包装在一个函数中(有兴趣的朋友不妨点进去看看)。我们现在先添加一些描述和测试语句,并运行看看吧,将上面的代码的SPEC_BEGIN和SPEC_END之间的内容替换为:
describe(@&SimpleString&,&^{&&&&&context(@&when&assigned&to&'Hello&world'&,&^{&&&&&&&&&NSString&*greeting&=&@&Hello&world&;&&&&&&&&&it(@&should&exist&,&^{&&&&&&&&&&&&&[[greeting&shouldNot]&beNil];&&&&&&&&&});&&&&&&&&&&&it(@&should&equal&to&'Hello&world'&,&^{&&&&&&&&&&&&&[[greeting&should]&equal:@&Hello&world&];&&&&&&&&&});&&&&&});&});&
describe描述需要测试的对象内容,也即我们三段式中的Given,context描述测试上下文,也就是这个测试在When来进行,最后it中的是测试的本体,描述了这个测试应该满足的条件,三者共同构成了Kiwi测试中的行为描述。它们是可以nest的,也就是一个Spec文件中可以包含多个describe(虽然我们很少这么做,一个测试文件应该专注于测试一个类);一个describe可以包含多个context,来描述类在不同情景下的行为;一个context可以包含多个it的测试例。让我们运行一下这个测试,观察输出:
VVStack[36517:70b]&+&'SimpleString,&when&assigned&to&'Hello&world',&should&exist'&[PASSED]&VVStack[36517:70b]&+&'SimpleString,&when&assigned&to&'Hello&world',&should&equal&to&'Hello&world''&[PASSED]&
可以看到,这三个关键字的描述将在测试时被依次打印出来,形成一个完整的行为描述。除了这三个之外,Kiwi还有一些其他的行为描述关键字,其中比较重要的包括
beforeAll(aBlock) - 当前scope内部的所有的其他block运行之前调用一次
afterAll(aBlock) - 当前scope内部的所有的其他block运行之后调用一次
beforeEach(aBlock) - 在scope内的每个it之前调用一次,对于context的配置代码应该写在这里
afterEach(aBlock) - 在scope内的每个it之后调用一次,用于清理测试后的代码
specify(aBlock) - 可以在里面直接书写不需要描述的测试
pending(aString, aBlock) - 只打印一条log信息,不做测试。这个语句会给出一条警告,可以作为一开始集中书写行为描述时还未实现的测试的提示。
xit(aString, aBlock) - 和pending一样,另一种写法。因为在真正实现时测试时只需要将x删掉就是it,但是pending语意更明确,因此还是推荐pending
可以看到,由于有context的存在,以及其可以嵌套的特性,测试的流程控制相比传统测试可以更加精确。我们更容易把before和after的作用区域限制在合适的地方。
实际的测试写在it里,是由一个一个的期望(Expectations)来进行描述的,期望相当于传统测试中的断言,要是运行的结果不能匹配期望,则测试失败。在Kiwi中期望都由should或者shouldNot开头,并紧接一个或多个判断的的链式调用,大部分常见的是be或者haveSomeCondition的形式。在我们上面的例子中我们使用了should not be nil和should equal两个期望来确保字符串赋值的行为正确。其他的期望语句非常丰富,并且都符合自然语言描述,所以并不需要太多介绍。在使用的时候不妨直接按照自己的想法来描述自己的期望,一般情况下在IDE的帮助下我们都能找到想要的结果。如果您想看看完整的期望语句的列表,可以参看文档的这个页面。另外,您还可以通过新建KWMatcher的子类,来简单地自定义自己和项目所需要的期望语句。从这一点来看,Kiwi可以说是一个非常灵活并具有可扩展性的测试框架。
到此为止的代码可以从这里找到。
Kiwi实际使用实例
最后我们来用Kiwi完整地实现VVStack类的测试和开发吧。首先重写刚才XCTest的相关测试:新建一个VVStackSpec作为Kiwi版的测试用例,然后把describe换成下面的代码:
describe(@&VVStack&,&^{&&&&&context(@&when&created&,&^{&&&&&&&&&__block&VVStack&*stack&=&&&&&&&&&&beforeEach(^{&&&&&&&&&&&&&stack&=&[VVStack&new];&&&&&&&&&});&&&&&&&&&&&afterEach(^{&&&&&&&&&&&&&stack&=&&&&&&&&&&});&&&&&&&&&&&it(@&should&have&the&class&VVStack&,&^{&&&&&&&&&&&&&[[[VVStack&class]&shouldNot]&beNil];&&&&&&&&&});&&&&&&&&&&&it(@&should&exist&,&^{&&&&&&&&&&&&&[[stack&shouldNot]&beNil];&&&&&&&&&});&&&&&&&&&&&it(@&should&be&able&to&push&and&get&top&,&^{&&&&&&&&&&&&&[stack&push:2.3];&&&&&&&&&&&&&[[theValue([stack&top])&should]&equal:theValue(2.3)];&&&&&&&&&&&&&&&[stack&push:4.6];&&&&&&&&&&&&&[[theValue([stack&top])&should]&equal:4.6&withDelta:0.001];&&&&&&&&&});&&&&&&&});&});&
看到这里的您看这段测试应该不成问题。需要注意的有两点:首先stack分别是在beforeEach和afterEach的block中的赋值的,因此我们需要在声明时在其前面加上__block标志。其次,期望描述的should或者shouldNot是作用在对象上的宏,因此对于标量,我们需要先将其转换为对象。Kiwi为我们提供了一个标量转对象的语法糖,叫做theValue,在做精确比较的时候我们可以直接使用例子中直接与2.3做比较这样的写法来进行对比。但是如果测试涉及到运算的话,由于浮点数精度问题,我们一般使用带有精度的比较期望来进行描述,即4.6例子中的equal:withDelta:(当然,这里只是为了demo,实际在这用和上面2.3一样的方法就好了)。
接下来我们再为这个context添加一个测试例,用来测试初始状况时栈是否为空。因为我们使用了一个Array来作为存储容器,根据我们之前用过的equal方法,我们很容易想到下面这样的测试代码
it(@&should&equal&contains&0&element&,&^{&&&&&[[theValue([stack.numbers&count])&should]&equal:theValue(0)];&});&
这段测试在逻辑上没有太大问题,但是有非常多值得改进的地方。首先如果我们需要将原来写在Extension里的numbers暴露到头文件中,这对于类的封装是一种破坏,对于这个,一种常见的做法是只暴露一个-count方法,让其返回numbers的元素个数,从而保证numbers的私有性。另外对于取值和转换,其实theValue的存在在一定程度上是破坏了测试可读性的,我们可以想办法改善一下,比如对于0的来说,我们有beZero这样的期望可以使用。简单改写以后,这个VVStack.h和这个测试可以变成这个样子:
&&-&(NSUInteger)&&&&&&&&-&(NSUInteger)count&{&&&&&return&[self.numbers&count];&}&&&&it(@&should&equal&contains&0&element&,&^{&&&&&[[theValue([stack&count])&should]&beZero];&});&
更进一步地,对于一个collection来说,Kiwi有一些特殊处理,比如have和haveCountOf系列的期望。如果测试的对象实现了-count方法的话,我们就可以使用这一系列期望来写出更好的测试语句。比如上面的测试还可以进一步写成
it(@&should&equal&contains&0&element&,&^{&&&&&[[stack&should]&haveCountOf:0];&});&
在这种情况下,我们并没有显式地调用VVStack的-count方法,所以我们可以在头文件中将其删掉。但是我们需要保留这个方法的实现,因为测试时是需要这个方法的。如果测试对象不能响应count方法的话,如你所料,测试时会扔一个unrecognized selector的错。Kiwi的内部实现是一个大量依赖了一个个行为Matcher和objc的消息转发,对objcruntime特性比较熟悉,并想更深入的朋友不放可以看看Kiwi的源码,写得相当漂亮。
其实对于这个测试,我们还可以写出更漂亮的版本,像这样:
it(@&should&equal&contains&0&element&,&^{&&&&&[[stack&should]&beEmpty];&});&
好了。关于空栈这个情景下的测试感觉差不多了。我们继续用TDD的思想来完善VVStack类吧。栈的话,我们当然需要能够-pop,也就是说在(Given)给定一个栈时,(When)当栈中有元素的时候,(Then)我们可以pop它,并且得到栈顶元素。我们新建一个context,然后按照这个思路书写行为描述(测试):
context(@&when&new&created&and&pushed&4.6&,&^{&&&&&__block&VVStack&*stack&=&&&&&&beforeEach(^{&&&&&&&&&stack&=&[VVStack&new];&&&&&&&&&[stack&push:4.6];&&&&&});&&&&&&&afterEach(^{&&&&&&&&&stack&=&&&&&&});&&&&&&&it(@&can&be&poped&and&the&value&equals&4.6&,&^{&&&&&&&&&[[theValue([stack&pop])&should]&equal:theValue(4.6)];&&&&&});&&&&&&&it(@&should&contains&0&element&after&pop&,&^{&&&&&&&&&[stack&pop];&&&&&&&&&[[stack&should]&beEmpty];&&&&&});&});&
完成了测试书写后,我们开始按照设计填写产品代码。在VVStack.h中完成申明,并在.m中加入相应实现。
-&(double)pop&{&&&&&double&result&=&[self&top];&&&&&[self.numbers&removeLastObject];&&&&&return&&}&
很简单吧。而且因为有测试的保证,我们在提供像Stack这样的基础类时,就不需要等到或者在真实的环境中检测了。因为在被别人使用之前,我们自己的测试代码已经能够保证它的正确性了。VVStack剩余的最后一个小问题是,在栈是空的时候,我们执行pop操作时应该给出一个错误,用以提示空栈无法pop。虽然在objc中异常并不常见,但是在这个情景下是抛异常的好时机,也符合一般C语言对于出空栈的行为。我们可以在之前的&when created&上下文中加入一个期望:
it(@&should&raise&a&exception&when&pop&,&^{&&&&&[[theBlock(^{&&&&&&&&&[stack&pop];&&&&&})&should]&raiseWithName:@&VVStackPopEmptyException&];&});&
和theValue配合标量值类似,theBlock也是Kiwi中的一个转换语法,用来将一段程序转换为相应的matcher,使其可以被施加期望。这里我们期望空的Stack在被pop时抛出一个叫做&VVStackPopEmptyException&的异常。我们可以重构pop方法,在栈为空时给一个异常:
-&(double)pop&{&&&&&if&([self&count]&==&0)&{&&&&&&&&&[NSException&raise:@&VVStackPopEmptyException&&format:@&Can&not&pop&an&empty&stack.&];&&&&&}&&&&&double&result&=&[self&top];&&&&&[self.numbers&removeLastObject];&&&&&return&&}&
进一步的Kiwi
VVStack的测试和实现就到这里吧,根据这套测试,您可以使用自己的实现来轻易地重构这个类,而不必担心破坏它的公共接口的行为。如果需要添加新的功能或者修正已有bug的时候,我们也可以通过添加或者修改相应的测试,来确保正确性。我将会在下一篇博文中继续介绍Kiwi,看看Kiwi在异步测试和mock/stub的使用和表现如何。Kiwi现在还在比较快速的发展中,官方repo的wiki上有一些不错的资料和文档,可以参考。VVStack的项目代码可以在这个上找到,可以作为参考。
CocoaChina是全球最大的苹果开发中文社区,官方微信每日定时推送各种精彩的研发教程资源和工具,介绍app推广营销经验,最新企业招聘和外包信息,以及Cocos2d引擎、Cocos Studio开发工具包的最新动态及培训信息。关注微信可以第一时间了解最新产品和服务动态,微信在手,天下我有!
请搜索微信号“CocoaChina”关注我们!
关注微信 每日推荐
扫一扫 浏览移动版}

我要回帖

更多关于 yeoman 中文 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信