Visual Studio 2010 Ultimate敏捷测试驱动开发
在本文中,笔者将介绍Visual Studio 2010 Ultimate Beta2版本中的MSF for Agile的Scrum和XP敏捷思想与VSTS2010强大的测试功能,通过对这些内容的阐述,让读者了解在VSTS2010中的敏捷测试驱动开发方法,以便于.NET开发人员能把敏捷驱动开发为导向的技术,应用在自己的项目和团队中,从而构筑出敏捷的开发团队。
1.引言
在前几篇的文章中提到过的Scrum,相信读者们都应该已经不陌生了,它的核心在于迭代,并且以每个sprint时间段的周期进行产品功能迭代。团队首先浏览开发需求,考虑可用技术,并对自身技术及能力做出评估,所有实践就是围绕着一个迭代和增量的过程来展开,而在每个迭代内部,可以使用测试驱动和持续集成的XP(eXtreme Programming,极限编程)工程实践。
XP,是最轻量级的开发流程,其最主要的精神是“在客户有系统需求时,给予及时满意的可执行程序”,所以最适合需求快速变动的方案。Scrum与XP所不同的是,Scrum只是一个敏捷过程框架,它并没有提供核心的价值观与指导原则,也缺乏具体的实践方法,例如,测试驱动开发、结队编程等。Scrum仅仅规定了实施的基本流程与检查表,它是一个开放的管理框架,重心在于项目管理,而不是指导团队成员如何进行开发。这既是Scrum的优点,因为它很灵活,能够适应大多数场景,也可以兼容并包地引入其他方法学所提倡的实践;同时也是Scrum存在的固有缺陷,使得它难以被实践。如果没有一位优秀的Scrum Master,而团队成员又缺乏自我组织和管理的能力,就会让开发过程变得一团糟,团队成员将会无所适从。
在团队中开发人员随时可以与客户进行有效沟通,撰写user stories以确认需求。简易快速的系统设计,撰写独立的验证程序以解决特殊困难的问题,并找出演算法即可丢弃验证程式。规划多次小型阶段的方案计划,并且以最快得速度完成每一阶段的程序交付客户,客户负责Acceptance tests;Coding前必须完成Unit Test与Acceptance tests程序,所有模组整合前都须经过Unit Tests;开发人员必须快速回应Bug和需求变更;要求二人一组使用一台电脑设计程序,当一人coding时,另一人负责思考与设计(结对编程);程序必须符合程序规范,并常做程序的重构(Refactoring)。
在Agile开发实践方面,Scrum可以借鉴XP提倡的结队编程以及测试驱动开发实现编码,通过重构对编码进行调整以适应需求的变化,Scrum为体,XP为用。XP开发流程的基本步骤,如图1所示。
图1 XP开发流程的基本步骤
测试驱动开发意味着你要先写一个自动测试,然后编写恰好够用的代码,让它通过这个测试,接着对代码进行重构,主要是提高它的可读性和消除重复,这将会对Agile Team整体素质要求较高。
时至今日,Agile Process的精神已经成为共识,但是没有一种固定的流程可以重复使用在不同的方案上,而且不管是RUP、XP、SCRUM、或其他的开发流程都允许相当大的弹性,我们必须按方案性质的不同,调整或混合出适合的开发流程,并允许团队在进行中做必要的弹性修改,才能够达成目标。
2.敏捷之驱动开发
在XP开发实践中的TDD(Test Driven Development),它有一个别称叫 Test-First Programming,要求开发的第一步是根据需求,必须先写单元测试程序,然后再写实现程序让符合需求的测试通过。我们知道XP中的需求是以“用户故事”(User Story)的形式描述的,而用户故事实质上就是一种软件“特性”(Feature)。TDD 讲的是如何通过编写“测试”,尤其是单元测试,来驱动软件的设计和编程。
系统测试从哪里来?来自系统需求。系统需求从哪里来?来自用户目标,TDD则也不例外。在需求不稳定的情况下,这样的TDD会有什么问题?会不会带来许多冗余的工作?答案是肯定的,这样必然会带来单元测试的不稳定,这就需要敏捷开发人员有相当强的抽象能力,抽象、界定出主要相对稳定需求就可以实施TDD。
敏捷团队可以采用在软件工程学里有比较成熟的OOAD(Object Orient Analysis & Design,面向对象的分析和设计)软件开发方法(参见笔者著作《我也能做CTO之程序员职业规划》的高级程序员技术能力),在用户需求层面找到,并抽象出相对不变的需求。OOAD科学分析法体现的是‘现实事实的抽象理解能力’,以业务为中心来分析解决问题,不涉及求解方案。分析阶段所做的主要工作是理解问题和需求构模,将现实世界中的问题映射到问题域,从而稳定主要需求。OOAD包括‘设计模式能力’,反映计算机世界来体现现实世界。
分析阶段主要是明确用户的功能需求,满足用户所需的系统部件及其结构。设计阶段则主要是确定实现用户需求的方法,即怎样做才能满足用户需求,并构造出系统的实现蓝图。
OOAD方法要求在设计中要映射现实世界中(指问题域,如图2所示)的对象和实体,如程序员、汽车、项目实施人员等。这就需要在设计中尽可能地接近现实世界,以最自然的方式表述实体。所以,面向对象技术的优点就是能够构建与现实世界相对应的问题模型(桥梁),并保持它们的结构关系和行为模式。
例如,我们通常做的系统分析是在假定需求不变的情况下进行的,这样可以把企业的资源配置到最优的程度,但是企业的需求是变化、不稳定的,那么以变化的需求为基础建立起来的软件系统当然也就不稳定了。需求是项目的根本,既然需求都是不稳定的,那么何以建立起稳定的企业信息系统呢?
图2 软件需求抽象示意图
采用OOAD开发的方法时的需求不稳定,可分析出这不稳定的东西就是对象。世界都是由对象组成的,而对象都是持久的,例如动物、植物已经有相当长的时间。虽然对象也在变化,动物、植物也在不断进化。但对象在一个相当长的时期内都存在,动植物的存在时间肯定比任何一家企业长久。面向对象开发方法的精髓就是从企业的不稳定需求中分析出企业的稳定对象,以企业对象为基础来组织需求、构架系统。这样得出的系统就会比传统的系统要稳定得多,因为企业的模式一旦变化,只需将稳定的企业对象重新组织就行了。
在敏捷XP中,采用的是TDD驱动软件的设计和编程实践,即,测试驱动开
发。笔者负责过很多项目的敏捷实践中,更喜欢UDD(Use Case-Driven Development)比较适合目前的国情。它可根据用户目标,编写软件需求,根据软件需求,编写系统(验收)测试,即,用户目标驱动。利用 UML 对软件的设计进行建模,这部分建模当然是敏捷的(agile)。简单的只需几秒钟可以迅速在人的大脑中完成,复杂的则可以画在纸上、白板上,记录在建模工具生成的电子文档中,当需求稳定后可以迅速转化成软件应用代码,在结合TDD会有很不错的效果,这种理论体系有些像太极原理,需求的变化看似武术中的招式,采用UDD见招破招,无招胜有招,这种客户的需求应变使得UDD更为敏捷。
3.实战VSTS2010驱动开发
在Visual Studio 2010中,敏捷测试驱动开发功能非常强大,微软把Scrum和XP敏捷思想融入到Agile过程框架之中。TFS2010中增强了团队源码版本管理、迭代开发和驱动测试开发模型等,从而给微软.Net开发人员非常大的帮助。VSTS2010测试马甲和单元测试过程,如图3所示。
图3 VSTS2010单元测试过程
IUT——在生产环境中最终交付而开发的软件。
Test Environment——测试环境。
测试驱动开发(TDD)基本过程:
(1)明确当前要完成的功能。可以记录成一个初始化测试清单(TODO)列表。
(2)快速完成针对一个功能的测试用例编写。
(3)测试代码编译通过,但测试用例通不过。
(4)编写对应的功能代码。
(5)测试通过。
(6)对代码进行重构,并保证测试通过。
(7)循环完成所有功能的开发。
·图书收藏实例
确定好backlog,进行sprint backlog,把story拆分成更小的故事,并在把故事拆分成任务,索引卡片参考图4所示。
图4 图书收藏Story索引卡
将案例分成任务,我们需要在很大程度上实现读者个人借阅图书的收藏集合。其中之一backlog索引卡,如图4所示。当读者到图书馆进行图书借阅中,会查询图书库所有相关类图书封面并选取其中自己最需要的几本书。这个过程叫做“书签”,图书系统将通过图书管理来支持这个活动。为图书借阅集合初始化测试清单,参考1所示。
表1 为图书借阅夹初始化测试清单
列出表中完成有关的大部分任务测试清单,测试重点放在确保我们添加和移除图书收藏夹的时候计数是正确的,以及集合的内容和是否可以恢复集合,驱动测试时间持续1到2小时的驱动编程实践中完成这个测试清单,并确保这个测试清单不需要再次分解这个任务,以实现这个目标。
·实现第一个测试
打开Microsoft Visual Studio 2010,创建一个C#测试项目,项目名称为LocalBookCollectionsTests,如图5所示。
图5 创建一个测试项目
清除原理项目方案自动生成的unit的C#测试文件,建立一个新的名称为CollectionsTests单元测试类,如图6所示。
图6 创建一个单元测试unit类
先用一些函数代码替换第一个测试中的语句,这样做驱动了产品代码Collections类的创建,并运行其Count属性。在CollectionsTests.cs类添加代码:
/// 创建一个测试清单
///
[TestMethod]
public void EmptyCollectionsCountShouldBeZero()
{
Collctions collctions = new Collctions();
Assert.AreEqual(0, collctions.Count);
}
重新编译生成这个解决方案,你将看到一个错误,因为没有为Collections类定义Count。创建Collections类,填入一下代码:
/// 定义Count
///
private int count;
public int Count
{
get
{
return count;
}
}
运行这个测试,输出EmptyCollectionsCountShouldBeZero()单元测试成功界面,如图7所示。
图7 EmptyCollectionsCountShouldBeZero单元测试成功
·搁置你的测试清单代码
为你的此次操作添加为一个版本控制搁置,这样就可以在将来常常返回到这个点(版本控制),在VS2010菜单打开View|Other Windows|Pending Changes,如图8所示。
图8 Vsts2010的View|Other Windows菜单
通常由于你并不想在所有相关单元测试通过之前,与团队的其他成员共享文件,因此保持VSTS存储库中搁置自己的文件版本,而不是将你的变更点签入到团队代码库的分支中。完成所有单元测试后,可以直接点击Check In 按钮将此代码加入到存储库中。Pending Changes搁置窗口,如图9所示。
图9 Pending Changes搁置窗口
Unshelve按钮可以进行版本回卷。点击Shelve按钮进行版本搁置,建立一个Test the Should Be Zero的版本搁置,如图10所示。
图10 创建版本搁置
·修复一个失败的测试和重构
现在我们处理清单上另外几个简单单元测试。它们在Collections对象中添加和删除各种Collection项,并验证Count熟悉返回正确的值。
首先在CollectionsTests.cs类中添加如下代码:
/// 修复一个失败的测试
///
[TestMethod]
public void EmptyCollctionsCountShouldIsOne()
{
Collections collections = new Collections();
collections.Add(new Collection("Label", new Uri("db://book0001")));
Assert.AreEqual(1, collections.Count);
}
生成这个项目(生成|生成项目),生成报错是因为Collection类缺少参数,如图11所示。
图11 缺少参数报错界面
添加一个unit新类Collection.cs,加入一下代码:
private Uri uri;
public Collection(string label, Uri uri)
{
this.label = label;
this.uri = uri;
}
public string Label
{
get
{
return label;
}
}
public Uri Uri
{
get
{
return uri;
}
}
替换Collections.Add()方法,修改Count属性返回count变量值。
/// 增加一个Count实例变量
///
public void Add(Collection collction)
{
count++;
}
再次生成这个项目,输出结果显示成功,如图12所示。
图12 输出单元测试成功结果
再次重复上面操作,创建一个版本搁置。
4.确认测试(BVT)
生成确认测试(BVT)是通过产生测试列表来检查软件,它通常作为一个生成任务在团队生成结束的时候执行。当编写好一个unit测试时,你可以加入到BVT中,确保任何时候在生存库环境下运行集成生成,相同的测试程序都可以依次执行。
我们可以把上面的EmptyCollctionsCountShouldBeZero()和EmptyCollctionsCountShouldIsOne()测试方法创建生成测试。打开Microsoft Visual Studio 2010菜单,点击Test|Windows,如图13所示。
图13 Test|Windows菜单
点击菜单项Test|Windows|Test List Editor,打开Test List Editor界面,如图14所示。
图14 Test List Editor界面
参考图14,点击界面“here”或者菜单Test|Create New Test List,创建一个新的测试列表,测试列表名称为BookCollectionBVT,如图15所示。
图15 创建一个新的BVT
同理,打开菜单项Test|Windows|Test View,打开Test View浏览框从而显示驱动单元测试程序,从Test View把EmptyCollctionsCountShouldBeZero和EmptyCollctionsCountShouldIsOne拖拽拖到Test List Editor面板中,为了确保这个测试是作为集成测试的一部分运行,点击BookCollectionBVT中所要测试程序的复选框。
点击Run Checked Tests按钮,运行这个测试程序,如图16所示。
图16 运行这个测试程序
运行测试结果界面,如图17所示。
图17 运行测试结果界面
这样,安装Microsoft Visual Studio 2010团队成员,在每个人的本机上开发环境上运行自己的单元测试之后,就可以添加并测试完成余下的那些索引卡下分解出来的测试列表单元测试程序清单,加入到BookCollectionBVT集成测试集合之中。
五、总结
Microsoft Visual Studio 2010的集成测试的功能特点结合MSF for Agile Software Development V5.0中的Scrum和XP敏捷过程框架,使从事在微软.NET技术相关工作方向的人们拥有了一把利剑,并且可以充分的协助编程人员开发出高质量的软件产品。
Scrum专注于聚焦在找到一个最小的迭代式项目管理框架,注重敏捷的计划、跟踪和管理,而没有把它强行绑定在某一种具体的工程技术和做法之上有关,这大概这也是它非常聪明的地方。既然没有明确限定和约束,那么就代表着开放,可以适用于不同类型、不同环境下的项目。
从Scrum和XP—>OOAD—>UDD和TDD,不禁让笔者想起太极阴阳理论,可以说太极是我们中国人千年的传统智慧,看待宇宙和世界的一种基本观点和思维方式。世界和宇宙是由阴和阳组成,两者既互为对立、矛盾,又相互依存、共生,和谐、统一地构成了整个宇宙。敏捷之道的精髓就在于客户、团队和人与人之间的沟通与互动、协作,所以,作为中国人尤其是中国的软件人,更应该开阔自己的思维,学会运用太极思想。
孙子兵法有云:兵无常势,水无常形,能因敌变化而取胜者谓之神。很多人都向往用兵如神的境界,想必也知道读万卷书不如行万里路,纸上谈兵的故事更是耳熟能详,除了以上所讲述的内容外,也需要充分的运用敏捷和进行大量的实践。
敏捷文化也决定管理,管理决定技术,因此实施敏捷应该只有具有先进文化的企业和团队,才能实现真正的敏捷变革,并从中获益……。
测试代码下载
我为it168籍稿,原文:http://tech.it168.com/a2009/1207/820/000000820565_1.shtml
———————————————————————
任何美好的事物只有触动了人们的心灵才变的美好;
孤独的时候看看天空里的雨,其实流泪的不只是你。
人生只有走出来的美丽,没有等出来的辉煌!
———————————————————————