很多人把学习C++语言当成学习VC了,我曾经就走过这样的弯路。当学了很长时间的VC后还是得回过头来学习C++语言本身。
那么学习C++从何处入手了?
C++语言相对于C语言来说引入了两个大的新东西,一个就是面向对象(具体来将就是类),另外就是模板技术(模板编程或者叫泛型编程是进来非常流行的技术,在C#中虽然还没有对泛型编程的支持,但是相信在将来也一定会加入这一功能),模板是C++中比较复杂的部分,但是作为一个真正的C++程序员,这部分很重要。尤其是对C++标准程序库的掌握尤为重要。
刚开始的时候千万不要直扑VC中的各种向导和设计器。因为依赖开发环境生成的很多代码会把我们搞糊涂,也不利于我们学习C++语言本身。我的建议就是生成一个空的控制台工程,然后自己向里面添加文件。
如下就是一个简单的控制台程序:
|
//robindy/list.cpp #include <iostream> using namespace std; int main() for(char c = \'a\'; c <= \'z\'; ++c) list::const_iterator pos; return 0; |
对using namespace std;的解释:所谓namespace,是指标识符的各种可见范围。C++标准程序库中的所有标识符都被定义于一个名为std的namespace中。
由于namespace的概念,使用C++标准程序库的任何标识符时,可以有三种选择:1、直接指定标识符。例如std::ostream而不是ostream.完整语句如下:std::cout << std::hex << 3.4 << std::endl;2、使用using关键字。
using std::cout;using std::endl;以上程序可以写成cout << std::hex << 3.4 << endl;3、最方便的就是使用using namespace std;这样命名空间std内定义的所有标识符都有效(曝光)。就好像它们被声明为全局变量一样。那么以上语句可以如下写:cout << hex << 3.4 << endl;
这段程序用到了标准模板库,在屏幕上打印字符a~z,其中main函数的标记式只有两种是被C++标准委员会接受的,只有以下两种写法是符合C++标准的,是可移植的。即:
| int main() { } 和 int main(int argc, char* argv[]) { } |
C++在main()的末尾定义了一个隐式的return 0; 但是在VC中必须显式的写出return语句。
在BCB中可以不写return而编译通过。
这段程序中用到了STL中的容器:链表。先是向链表中插入26个字母,然后从遍历链表,输出字符。
我不建议初学者一开始就从模板库入手,但是我建议应该逐渐地有意识地学习模板库。如我们应该熟悉cout和cin的用法(位于iostream),而减少使用老式的C函数库中printf和sc anf等。
从控制台入手的好处就是避免我们理解VC中向导等工具生成的其他代码,整个程序的流程很清楚。新手学习VC的一大难点就是搞不清楚整个程序的流程(从那条语句开始执行,然后从那条语句退出。MFC做了太多封装,掩盖了事实的真相,^_^)。通过控制台我们可以很快地学习C++语言中的很多新特性。如类的封装、继承和多态等。通过这个时期的学习,要能够掌握三个东西: C++关键字、语法(重点是和面向对象有关的,以及模板)、C++标准程序库(知道怎么使用即可,要彻底掌握需要很多时间和精力)。至于与界面有关的东东(MFC中很大一部分是与界面相关的类,所以我认为MFC很臃肿而无聊!回头看过以前用MFC写的程序,有一种“垃圾”的感觉。)
自己做个测试:写一个控制台程序,在其中体现出类的继承,函数重载,动态多态(通过虚函数实现),数据封装,C++标准库的运用。
如果你能够轻松搞定,恭喜你,你已经通过C++语言关了。不过C++实在是一个复杂的东东,其中有各种千奇百怪的语法现象,如果没有三、五年的功力,千万不要说自己懂C+ +.^_^.推荐书籍《Thinking in C++》(有精力的话,可以直接读原版)
《Essential C++》
本来我计划继续说说如何来进入C++世界的,但是琢磨了一下,觉得还是要先解决一个问题:为什么要学习C++?我觉得在软件开发这个行当了里除了为了生计外,学习新东西都是应该以兴趣为导向的。所以撇开我个人对C++的偏爱,我想为你树立起学习C++的信心和兴趣。当初我对自己学习C++的第一个忠告就是:不能半途而废!起初是兴趣驱动,后来则是生计所需,最后还是回归到了兴趣。毕竟我从中得到了乐趣,这就足够了。在学一个新东西前,解决动机问题很重要。就如同杀人一样,如果只是突然兴起,那么等尝试了以后,是没有成就感的。革命先烈们为我们作出了很好的榜样,就算我们在学习C++的道路上遇到了太多困惑和痛苦,但是我们毕竟为自己的信念做了努力,我们知道自己在做什么,知道自己在追求什么。
C++适合做什么样的开发?
C++是一门广泛用于工业软件研发的大型语言。具有很高的复杂性和解决问题的能力。C++不仅在开发上极具价值,同时在学术界也就有很高的价值。有关C++的文章应该可以用浩如烟海来形容了吧。C++的世界级经典书籍也是数不胜数。然而,目前开发语言是如此地繁荣,就连微软也在推出了新的开发语言C#。一个不可否认的现实是,在低阶程序设计领域,C++挤压着C同时也在承受着C的强烈反弹,前段时间看了据说是微软操作系统源代码的东东,其中很多还是C语言。而在高阶程序设计领域,Java和C#正在不断蚕食着C++的地盘。也许Java和C#的狂潮终将迫使C++回归本位— 回到它有着根本性优势的开发领域:低级系统程序设计、高级大规模高性能应用设计、嵌入式程序设计、通用程序设计以及数值科学计算等。果真如此,我认为这未尝不是一件好事。电力系统软件所要求的高性能和大规模数值计算正是C++所擅长的。就我所接触的南瑞和鲁能,很多涉及到电力系统计算的软件如PAS等,都是用C++来开发的。在电力系统软件开发这块阵地,C++大有用武之地。C++吸引如此之多的智力投入,以至于这个领域的优秀作品,包括重量级的软件产品、程序库以及书籍等,数不胜数。在C++之父Bjarne Stroustrup的个人主页上,有一页列出了一些(全部或大部分)使用C++编写的系统、应用程序和库。
下面是一些例子(摘自荣耀网站):o Adobe Systems:所有主要应用程序都使用C++开发而成,比如Photoshop & ImageReady、Illustrator和Acrobat等。
·Maya:知道“蜘蛛人”、“指环王”的电脑特技是使用什么软件做出来的吗?没错,就是Maya. o Amazon.com:使用C++开发大型电子商务软件。
·Apple:部分重要“零件”采用C++编写而成。
·AT&T:美国最大的电讯技术提供商,主要产品采用C++开发。
·Google:Web搜索引擎采用C++编写。
·IBM:OS/400. o Microsoft:以下产品主要采用C++(Visual C++)编写:o Windows XP Windows NT:NT4、2000 Windows 9x:95、98、Me Microsoft Office:Wo rd、Excel、Access、PowerPoint、Outlook Internet Explorer,包括Outlook Express Visual Studio:Visual C++、Visual Basic、Visual FoxPro .NET Framework类库采用C #编写,但C#编译器自身则使用C++编写而成。Exchange SQL Server FrontPage Project所有游戏……
·KDE:K Desktop Environment(Linux)。
·Symbian OS:最流行的蜂窝电话OS之一。
很多新手特别容易会对自己所学习的东东产生疑惑、迷茫。觉得自己学这个东西,花了这么多时间有没有用,会不会过时?这种思想很普遍。在一些论坛上经常会看到一些各语言的优劣比较,知道自己所学语言的优劣也好,但是如果一味停留在这个层面就没有用了。
任何语言都只是工具而已。重要的是使用工具的人!就我个人的经验来讲,真正处于业界搞开发的人都愿意使用成熟的、为自己所熟知的技术来完成工作。而新手都喜欢用一些比较新的技术来做开发,而且喜欢追求新奇(从界面很容易看出来,花花绿绿的界面多半出自新手)。其实,安于用一些效率可能低下、扩展性和维护性差的方法来解决问题并不是开发人员的错。他们只是在完成工作而已。但是作为一个真正有上进心的开发人员,我们应该使用更优雅和高效的编程技术,这才是我们逐渐变成编程“大牛”的好习惯。老是停留在原地,很容易被淘汰的。在软件开发这个行当,尤其如此。无论是对学生,还是一线开发人员,我觉得都不应该产生“书读够了”的感叹!我有时候喜欢将以前看过的书翻出来再看,每次总能体会到一些新东西。有关C++语言的书籍更是如此,而且我觉得我所起的题目不是很好。为什么?因为我觉得学习语言还只是新手跨入软件开发“地狱”的第一步,单单学习语言本身是远远不够的,还要学习相关的程序库(C++当然首选是先学习C++标准程序库)、相关的平台技术(如。NET),说得更远一点,还要锻炼对目标问题的分析、归纳能力等等。工作之前,技术路线自己作主,工作之后,绝大多数程序员将被公司技术路线左右。所以,趁现在还有时间,可以学一些自己感兴趣的。如果想搞软件开发,特别是电力系统软件的开发,学好C++不会令我们失望。当我们进入C++的前门,然后经过一段黑暗之路,再从后门出来到达光明顶后,我们会体味到“一览众山小”的感觉。
推荐书籍:《编程高手箴言》梁肇新(用过超级解霸的都应该知道吧,^_^)写的第一本书,其中有几章还是值得一读的。在这本书中,梁告诉我们,学东西要耐心,要耐得住“寂寞”,走自己的路,让别人去“说”吧!
最近比较忙,原来打算紧扣主题讲讲一些具体的C++语言的细节的,但还是抽不出大段的时间了。所以,现在只能再漫谈一些关于C++的故事了。
C++源于C语言,还记得很久以前学习C语言的时光(那是一段快乐而充实的时光),可是现在学习C++,并不是在C的基础上加上了类而已,如果这样认为,我们是耍不好C++的。因此,C++绝不是C的升级或扩充,我们应该把C++当作一门新语言来学习(C++之父Bjarne Stroustrup语)。
写程序首先希望是程序能正确执行,其次是效率能够被接受,再次就是易于维护。C++是一个难学易用的语言。C++提供了太多可选择的东西,而且使用使用C++来写程序可以有四种思考模式:基于过程、基于对象、面向对象和泛型。我们使用一种语言来写程序,并不意味着就是使用语言本身,换句话说,我们更多的时候是使用程序库在写程序。比如MFC、STL、ATL、VCL等等。其中要使用C++来写出结构优美、性能卓越、代码简洁、易于维护的代码,首推C++标准程序库。STL对效率做了严格的要求,而且使用STL写出来的程序简洁美观(前段时间我特意贴了一个要求对若干整数进行排序的帖子,其实目的就是用来展示STL的简洁优雅)。一旦习惯使用泛型思维来考虑问题,我们能够充分体会到模板带来的美!
对于数值计算来说,C++标准程序库可以充分满足现代化服务和商业计算对数据、信息的即时回应的要求。
我觉得学好一门语言最重要的就是实践。也就是多“写”!“工程经验之积累”对已具有一段开发时间的程序员而言,非常重要!只有在不断的积累中,我们才能渐渐体会到C++语言中的一些背后的东西。对于这点,没有大量程序代码写作经验的菜鸟,也可以借助《Effective C++》先攒一些经验值。《Effective C++》是一本好书!。Meyers的书绝对值得一读,Meyers可以说当今C++社群中数一数二的技术专家。
以下文字应该是去年所涂鸦而成,主要是关于动态内存分配的,在这里将其重新看了看,觉得还是写得太浅薄了。因为内存是程序运行的“运动场”,对场地的了解程度会直接影响到我们程序运行的流畅度和稳定性。
C++提供了操作符new来在堆上分配内存,操作符delete来释放内存。有些情况下,我们需要对内存的分配和释放进行更好的控制。许多程序创建和释放一些重要类的大量的对象,如tree nodes,linked lists links,points,lines,messages,etc.使用通用的内存分配器如new和delete来进行这些对象的分配和释放有时将支配程序的运行时间和内存需求。
两方面的因素:通用内存分配操作的运行和空间的耗费以及不同对象大小引起的内存碎片。类使用定制的内存分配器将加快模拟器、编译器和类似程序的执行速度。
例外一种需要更好的内存控制的情况是:需要在有限资源的情况下长时间不间断运行的程序。实时系统经常需要用最少的耗费来获取有保证的可预期的内存。这也就导致了更好的内存控制的需要。一般来说,这些程序都避免使用动态的内存分配,而使用特殊目的的内存分配器来管理有限资源。
此外,还有一些情况下由于硬件或系统的要求,需要将对象放在指定的内存位置。这也需要进行定制的内存管理(通过重载new来加以实现)。
在C++ Release 2.0中,为了满足以上需求,内存管理机制做了相应的修改。主要是引进了operator new [] 和 operator delete []. new操作符的作用范围(Scope for operator new Functions)
操作符(Operator) 范围(Scope)
::operator new Global
class-name::operator new Class
operator new的第一个参数必须是类型size_t(在STDDEF.H中定义的类型),返回类型为void *.
当分配内建(built-in)类型的对象、未包含用户自定义的new操作符函数的类对象、任何类型的数组时,使用全局new操作符函数。当在类中自定义new操作符时,分配该类对象的内存时,调用该类的new操作符。如下:
| #include #include class Blanks { public: Blanks(){} void *operator new( size_t stAllocateBlock, char chInit ); }; void *Blanks::operator new( size_t stAllocateBlock, char chInit ) { void *pvTemp = malloc( stAllocateBlock ); if( pvTemp != 0 ) memset( pvTemp, chInit, stAllocateBlock ); return pvTemp; } int main() { Blanks *a5 = new( 0xa5 ) Blanks;//创建对象Blanks,并且初试化为0xa5 return a5 != 0; } |
new操作符可以重载,而delete却不行。因为等到需要释放的时候,我们所能得到的就是一个指针。而且该指针可能不是原先的对象类型指针(有可能进行了类型转换)。实际上,当使用new获得一个指向一片内存的指针时,在该片内存前有一个指示器(indicator)
,记录实际分配的内存数量。当调用delete时,可以获知需要释放的内存大小。
数组的释放(Deallocating Arrays):
| void f( ) { X* p1 = new X[10]; //... delete [] X; } |
为什么不使用delete [10] X;来释放内存?Bjarne Stroustrup称这种做法容易导致错误,而将记录元素个数的任务放在delete的实现中了。
至于为什么C++中未内建垃圾收集器(Garbage Collection)的原因,看《C++语言的设计和演化》(En) Bjarne Stroustrup 机械工业出版社(俗称:D&E)可以得到答案。
此外,C++标准库中提供了一种智能型指针auto_ptr,这种指针可以帮助我们防止“被异常抛出时发生资源泄漏”。但是缺点是该智能型指针不能指向数组,因为其内部释放内存是通过delete而非delete [] 来进行的。所以,只能使用其来指向一个单个对象。
模板部分是C++中比较难的部分,也是C++的魅力所在。以下文字是我以前看过的,具体出处不清楚了。今天稍微整理了一下,作为模板介绍的一个单元。
为什么要使用模板
对于除类型之外,其余都相同的函数(譬如quicksort),我们一般有3种解决办法。
1、针对每个不同的类型重复地编写函数实体(C语言的做法):
int* quicksort(int a[]) {…… }
double* quicksort(double a[]) {…… }
…
2、使用Object(Java的做法)或者void*
缺点有两个
效率问题方面也有问题
类型检查问题
3、使用宏预处理机制
缺点:只是愚蠢的文本替换,而且也不会考虑作用域和类型安全。
然而,应用模板却可以避免这些缺点,我们可以编写:
template
T* quicksort(T a[]) {…… }
优点:
代码简洁优雅,所有参数类型都以T来代替,真正实现了类型无关性。
更好的类型安全性,所有的类型检查都是在编译期进行,而且避免使用指针。
不存在继承,效率高。(1)没有虚函数;(2)所有的一切工作都是在编译期完成,大大提高运行效率。
目的:告诉编译器如何做出最佳的选择,而且这种选择全部是在编译期完成的。
模板的机制:特化 和 实参演绎
| 1、特化 基本模板: template class A { // (1) void f(T1 a, T2 b); } 局部特化(偏特化): template class A { // (2) void f(int a, T2 b); } 或者 template> class A { // (3) void f(T a, T b); } 全局特化(显式特化): template<> class A { void f(int a, int b); // (4) } 使用示例: A* p1; //将使用(4) ——全局特化 A* p2; //将使用(3) ——局部特化 A* p3; //将使用(2) ——局部特化 A* p4; //将由(1) ——基本模板——生成 //A |
优点:由:全局特化->局部特化->基本模板,这种特化顺序的选择与匹配(重载解析规则)是由编译器自动进行的,无需人工参与。
可以根据不同的情况(诸如类型不同,条件不同),给出不同的实现,从而获得更加灵活的针对性。
可以针对任何变化,改善了程序的扩展性。
2 实参演绎
| T const& f(T const& a, T const& b) { return a + b; //1处 } int g = f(1,2); |
实际上f(1,2)要匹配的函数是int const& f(int const&,int const&);
而这个函数又是怎么来的呢?
优点:
再也无需提供一对尖括号和里面的实参,诸如f(1,2),有了实参演绎,我们就可以写成f(1,2)。
模板的应用
1、标准库(STL)——到处都是模板代码
标准库=算法+容器+迭代器
如list /
2、类型无关性(T)
3、trait和policy
(1)trait: 主要用到了许多typedef和特化,指定的是一种特性。
| // traits/accumtraits3.hpp template lass AccumulationTraits; c template<> class AccumulationTraits { public: typedef int AccT; static AccT const zero = 0; }; template<> class AccumulationTraits { public: typedef int AccT; static AccT const zero = 0; }; template<> class AccumulationTraits { public: typedef long AccT; static AccT const zero = 0; }; (2)policy:通常表现为某个函数,指定的是一种行为 class SumPolicy { public: template static void accumulate (T1& total, T2 const & value) { total += value; } }; (3)trait和policy的用法: template > class Accum { public: typedef typename Traits::AccT AccT; static AccT accum (T const* beg, T const* end) { AccT total = Traits::zero(); while (beg != end) { Policy::accumulate(total, *beg); ++beg; } return total; } }; |
4、Metaprogramming
编译期计算、递归的思想
5、新形式的设计模板
(第三、第四、第五点以后再详细介绍)
《C++ Templates中文版》的具体介绍
第1部分介绍了模板的基本概念,以教程的风格来介绍这些基本概念。
第2部分阐述了模板的语言细节,可以作为一本基于模板的构造的参考手册。
第3部分介绍了C++模板所支持的基本设计技术,范围覆盖从微小的概念一直延伸到复杂的用法;一些技术在别的书籍都没有出现过。
第4部分基于前两部分,深入讨论了各种使用模板的普通应用程序。
学一个月,可以用VC写一些小程序自己玩玩
学两个月,可以用VC写像样点的东西在周围人面前炫炫
学三个月,可以用VC给老板开始干活了
学六个月,开始重头去学C++
学一年后,决定要不要继续,if(继续) 学习MFC、ATL、STL、C#、BCB、Network、Database、Algorithm... else 开始就是个错误
学三年后,学会怎么来用编程语言来解决问题,VC、BCB等都只是解决问题的工具。这时候
你如果还在学C++,你可以从事软件开发这个很有“前途”的职业了。
游戏测试起因
近几年来,网络游戏成了网络最新的弄潮儿,从盛大之传奇般的掘起,吸引了无数公司的眼球。但由于随着玩家的品位的升高,代理费用的上升,单一的代理国外游戏的模式已经很难在国内立足,而有中国传统文化特色的网络游戏则在国内大受欢迎,比如剑侠情缘,大话西游等一些国内的精典之作已经进入了一流网游的阵营。与此同时随着大家对网游稳定性,可玩性要求的升高,网络游戏测试开始成为大家关注的话题。
游戏测试与软件测试的区别
游戏测试作为软件测试的一部分,它具备了软件测试所有的一切共同的特性:
* 测试的目的是发现软件中存在的缺陷。
* 测试都是需要测试人员按照产品行为描述来实施。产品行为描述可以是书面的规格说明书,需求文档,产品文件,或是用户手册,源代码,或是工作的可执行程序。
* 每一种测试都需要产品运行于真实的或是模拟环境之下。
* 每一种测试都要求以系统方法展示产品功能,以证明测试结果是否有效,以及发现其中出错的原因,从而让程序人员进行改进。
总而言之,测试就是发现问题并进行改进,从而提升软件产品的质量。游戏测试也具备了以上的所有特性,不过由于游戏的特殊性,所以游戏测试则主要分为两部分组成,一是传统的软件测试,二游戏本身的测试,由于游戏特别是网络游戏,它相当于网上的虚拟世界,是人类社会的另一种方式的体现,所以也包含了人类社会的一部分特性,同时它又是游戏所以还涉及到娱乐性,可玩性等独有特性,所以测试的面相当的广。 我们称之为游戏世界测试,主要有以下几个特性:
* 游戏情节的测试,主要指游戏世界中的任务系统的组成,有人也称为游戏世界的事件驱动,我喜欢称为游戏情感世界的测试。
* 游戏世界的平衡测试,主要表现在经济平衡,能力平衡(包含技能,属性等等),保证游戏世界竞争公平。
* 游戏文化的测试,比如整个游戏世界的风格,是中国文化主导,还是日韩风格等等,大到游戏整体,小到NPC(游戏世界人物)对话,比如一个书生,他的对话就必需斯文,不可以用江湖语言J。
游戏测试概述
很多人有这样一个观点:“就是在软件开发完毕后,再进行测试。”殊不知,这种关点是有悖于软件开发的生命周期的,软件缺陷的发现必须是越早越好,这样才可以有效的规避风险,而在“最后进行测试”的测试观念的指导下测试工作必将会产生很多问题,这种观念的错误在于:生命周期中的“测试阶段”表明在该阶段测试工作是主要的工作,而不是说,测试工作只发生在“测试阶段”。通常,到了测试阶段,测试的主要任务是运行测试,形成测试报告。而想要提高游戏的质量,则必需要做到测试的早期介入,诸如测试计划,测试用例的确定以及测试代码的编写等等都是要在更早的阶段进行。如果你把测试完全放在最后阶段,就错过了发现构架设计和游戏逻辑设计中存在严重问题的最好时机,到那时,要修复这些缺陷将很不方便,因为缺陷已经扩散到系统中去了,所以这样的错误将很难寻找与修复,代价更高。
要了解如何测试游戏必需了解如何做游戏,了解它的开发过程,才能真正的测好游戏。游戏要成功,其基本的必要条件有三。分别为Vision(设计)、technology(技术)和Process(过程)。三个条件,缺一不可如图所示:

图:游戏开发三大基石
* Vision则是对游戏还没有实现的总体上的把握,前瞻性的理解与策略的考量。
* Technology:有了vision,如果没有技术的话,则各种美妙的想法只能停留在虚无缥缈的阶段,通过技术来实现Vision。
* Process:有了Vision作为指导,有了技术作为保证,也不一定能够把好的想法转换成高质量的游戏。要创造高品质的游戏,尚缺重要的一环,即过程,制造游戏是一个非常是一个长时间的动态过程。游戏产品的质量则是要靠动态过程的动态质量来进行保证。过程由很多复杂的相互牵制的环节与部件组成,如果任意的环节或者是部件出了问题都会对最终的产品形成质量上的影响。因此对这个动态的过程,一定要有规划与控制,以保证按步就班,按质按时完成工作。
游戏测试与开发过程的关系
CMM (Software Capability Maturity Model)软件成熟模型,大家都比较熟悉了,但在实施的过程中却存在这样那样的问题,对于游戏开发就更没有一个固定的路可以讲了,我们的团队是一个长期的游戏开发团队,对游戏开发有着很深的认识,我们认为游戏的Process(过程)实际上也是软件过程,不过是特殊的游戏软件开发过程,各个生命周期还是相通的。所以我们总结一套以测试作为质量驱动的、属于自己的开发过程。下图是游戏的迭代式开发过:

图:游戏迭代式开发与测试
由于网络游戏的生命周期也是3、4年,所以采用迭代式的开发过程,既可以适应网络游戏本身这种长周期的开发,又可以利用RUP的迭代式开发的优点与CMM的里程碑控制,从而达到对游戏产品的全生命周期的保证。
在游戏开发过程中,通用软件的需求分析阶段被策划所代替,但起的作用是一样的,明确游戏的设计目标(包括风格,游戏玩家群),游戏世界的组成,为后期的程序设计,美工设计,测试提出的明确的要求。由于开发是一个阶段的过程,所以测试与开发的结合就比较容易,从图上我们可以看到测试的工作与游戏的开发是同步进行的,每一个开发阶段中测试都进行了参与,能够深入的了解到系统的整体与大部分的技术细节,从而从很大程度上提高了测试人员对错误问题判断的准确性,并且可以有效的保证重要游戏系统的稳定。
游戏策划与测试计划
测试过程不可能在真空中进行。如果测试人员不了解游戏是由那几个部分组成的,那么执行测试就非常的困难,同时测试计划可以明确测试的目标,需要什么资源,进度的安排,通过测试计划,既可以让测试人员了解此次游戏测试中那些是测试重点,又可以与产品开发小组进行交流。在企业开发中,测试计划书来源于需求说明文档,同样在游戏开发过程中,测试计划的来源则是策划书。策划书包含了游戏定位,风格,故事情节,要求的配制等等。在策划评审中我们的高级测试人员可以参与进来,得到详细的游戏策划书,从里面了解到游戏的组成,可玩性,平衡(经济与能力),与形式(单机版还是网络游戏),而我们测试在这一阶段主要的事情就是通过策划书来制定详细的测试计划,主要分两个方面一是游戏程序本身的测试计划,比如任务系统,聊天,组队,地图等等由程序来实现的功能测试计划,二是游戏可玩性有测试计划,比如经济平衡标准是否达到要求,各个门派技能平衡测试参数与方法,游戏风格的测试,三是关于性能测试的计划,比如客户端的要求,网络版的对服务器的性能要求。同时测试计划书中还写明了基本的测试方法,要设计的自动化工具的需求,为后期的测试打下良好的基础。同时由于测试人员参与到策划评审,资深的游戏测试人员与产品经理由于对游戏也有很深入的了解,会对策划提出自己的看法,包含可玩性,用户群,性能要求等等并形成对产品的风险评估分析报告,但这份报告不同于策划部门自己的风险分析报告,主要从旁观者的角度对游戏本身的品质作充分的论证,从而更有效的对策划起到控制的作用。
游戏设计与测试
设计阶段是做测试案例设计的最好时机。很多组织要么根本不做测试计划和测试设计,要么在即将开始执行测试之前才飞快地完成测试计划和设计。在这种情况下,测试只是验证了程序的正确性,而不是验证整个系统本该实现的东西。而我们的测试则会很明确,因为我们的测试计划已经写的很明确,需要测试那些游戏系统,但是我们还需要了解系统的组成,而设计阶段则是设计系统的过程,所有的重要系统均是用UML状态图进行了详细的描述,比如用户登陆情况。如图2:

图2用户登陆情况
在我们的团队中资深的测试人员要具备的一项基本的素质就是可以针对UML的用例图,时序图,状态图来设计出重要系统的测试案例,只有重要系统的质量得到充分的测试,游戏程序的质量才可以得到充分的保证。比如上图中就是一个用户登陆游戏系统的时序图。从这里我们可以很明确的了解玩家是如何验证并登陆系统的,在这个过程中要与那些对象进行交互,比如这里我们就是三个系统之间的交互,客户端(玩家部分),网关,账号服务之间的一个时序变化关系,为了能够完整的对这个流程进行测试,我们必需设计出可以覆盖整个流程的测试案例,并考虑其中可能的非法情况,因为这个时序图只是考虑了用户正常登陆成功的情况,并没有考虑密码错误,通信失败等许多可能存有的情况,并形成完整的测试案例库,从而对登陆系统的系统化测试做了充分的准备。同时通过这张图,性能分析人员还可以分析出可能存的性能瓶颈,比如这里可能有的瓶颈如下,总网关是否可以达到多少用户的并发,是如果达不到,是否可以采用分布式部署或是支持负载平衡,三者之间的网络带宽的比例分配,账号服务器是否可以承载多个网关的连接请求,最大连接请求可以达到多少等等,同时会针对这些风险做性能测试的设计,并提出自动化测试的需求,比如模拟玩家登陆的压力工具等等。
同时在设计评审时,测试人员的介入可以充分的对当前的系统构架发表自己的意见,由于测试人员的眼光是最苛刻的,并且有多年的测试经验,可以比较早的发现曾经出现的设计上的问题,比如在玩家转换服务器时是否作了事务的支持与数据的校验,在过去设计中由于没有事务支持与数据的校验从而导致玩家数据丢失, 而这些风险可以在早期就规避掉。上面所说的是对游戏程序本身的测试设计,对于游戏情节的测试则可以从策划获得,由于前期的策划阶段只是对游戏情节大方向上的描述,并没有针对某一个具体的情节进行设计,进入设计阶段时,某个游戏情节逻辑已经完整的形成了,策划可以给出情节的详细设计说明书,称为任务说明书,通过任务说明书我们可以设计出任务测试案例,比如某一个门派的任务由那些组成,我们可以设计出完整的任务测试案例,从而保证测试可能最大化的覆盖到所有的任务逻辑,如果是简单任务,还可以提出自动化需求,采用机器人自动完成。
游戏测试与开发
开发与测试一直有人认为是不可以平行进行的,必需要先开发后测试,但是软件的开发过程又要求测试必须早期介入,但在这里这种矛盾得到了很好的解决。我们采用了每日编译,将测试执行和开发结合在一起,并在开发阶段以编码--测试--编码--测试的方式来体现。也就是说,程序片段一旦编写完成,就会立即进行测试。普通情况下,先进行的测试是单元测试,但是一个程序片段也需要相关的集成测试,甚至有时还需要一些特殊测试。特别是关于接口测试,像游戏程序与任务角本、图片的结合,大家都认为需要提前测试,通过每日编你可以把已经写好的程序片段接合起来,形成部分的集成测试,从而有效的体现的接口优先测试的原则。同时由于软件测试与开发是并行进行的,并且实行的是软件缺陷优先修改的策略,所以很少会出现缺陷后期无法修改的情况,并且由于前期的测试案例的设计与自动化工具的准备,我们不需要投入太多的人力就可以极高的保证游戏软件的产品质量,特别是重要系统的质量。由于我们的游戏程序是每日不断的完善,所以集成测试也在同步的进行之中,当开发进入最后阶段时,集成测试也同步的完成了。这里有一个原则,也就是我前面所说的,测试的主体方法和结构应在游戏设计阶段完成,并在开发阶段进行补充(比如在游戏开发中会有相应的变动,或是某个转移变地址的变化,这就需要实时的更新)。这种方法会对基于代码的测试(开发阶段与集成阶段)产生很重要的影响,但是不管在那个阶段,如果在执行前多做一点计划和设计,都会大幅度的提高测试效率,改善测试结果,同时还有利于测试案例的重用与测试数据的分析,所以我们的测试计划是在策划时就形成了,为后继的测试形成了良好的基础。
集成测试阶段
集成测试是对整个系统的测试。由于前期测试与开发的并行,集成测试已经基本完成,这时只需要对前期在设计阶段中设计的系统测试案例运行一下就OK 了。我们主要的重心在集成测试中的兼容性测试,由于游戏测试的特殊性,对兼容性的要求特别高,所以我们采用了外部与内部同部进行的方式,内部我们有自己的平台试验室,搭建主流的硬软件测试环境,同时我们还通过一些专业的兼容性测试机构对我们的游戏软件做兼容性分析,让我们的游戏软件可以跑在更多的机器上。
游戏可玩性测试
游戏可玩性测试也是非常重要的一块,主要包含四个方面:
* 游戏世界的搭建,包含聊天功能,交易系统,组队等可以让玩家在游戏世界交互的平台。
* 游戏世界事件的驱动,主要指任务。
* 游戏世界的竞争与平衡。
* 游戏世界文化蕴涵,游戏的风格与体现。
这种测试主要体现在游戏可玩性方面,虽然策划时我们对可玩性作了一定的评估,但这是总体上的,但一些具体的涉及到某个数据的分析,比如PK参数的调整,技能的增加等一些增强可玩性的测试则需要职业玩家对它进行分析,这里我们主要通过三种方式来进行:
* 内部的测试人员,他们都是精选的职业玩家分析人员,对游戏有很深的认识,在内部测试时,对上面的四点进行分析。
* 利用外部游戏媒体专业人员对游戏作分析与介绍,既可以达到宣传的效果,又可以达到测试的目的,通常这种方式是比较好的。
* 利用外部一定数量的玩家,对外围系统的测试,他们是普通的玩家,但却是我们最主要的目标,主要的来源是大中院校的学生等等,主要测试游戏的可玩性与易用性,发现一些外围的Bug。
游戏进入到最后阶段时,还要做内测,公测,有点像应用软件的beta版的测试,让更多的人参与测试,测试大量玩家下的运行情况。
可玩性测试是游戏重要的一块,只有玩家的认同,我们才可能成功。
性能测试与优化
最后要单独提一下的是性能优化,在单机版的时代,性能的要求并不是很高,但是在网络版的时代,则是两个完全不同的概念,主要包含了以下几个方面:应用在客户端性能的测试、应用在网络上性能的测试和应用在服务器端性能的测试。通常情况下,三方面有效、合理的结合,可以达到对系统性能全面的分析和瓶颈的预测。不过在测试过程中有这样一个原则,就是由于测试是在集成测试完成或接近完成时进行,要求测试的功能点能够走通,这时你首先要进行优化的是数据库或是网络本身的配制,只有这样才可以规避改动程序的风险。同时性能的测试与优化是一个逐步完善的过程,需要前期的很多的工作,比如性能需求,测试工具等等,不过由于前期工作的完善,这些都在前期完成了。这里我只做原则性的描述。
数据库的优化的原则主要是这样的,首先是索引进行优化,由于索引的优化不需要对表结构进行任何改动,是最简单的一种,又不需要改动程序就可能提升性能若干倍,不过要注意的是索引不是万能的,若是无限的增加会对增删改造成很大的影响。其次是对表,视图,存储过程的优化。不过在分析之前需要知道优化的目标,客户行为中那些SQL是执行的最多的,所以我们必需借助些SQL的跟踪分析工具,例如SQLProfile,SQLExpert,等工具,这样会迅速的定位问题。
关于网络的优化,这里我所说的并不是针对网络本身的优化,而是对游戏本身的网络通信的优化,所以它是与程序的优化是结合在一起的,首先也是发现问题,通过Monitor与Sniff先定位是什么应用占用了较多的网络流量,由于网络游戏的用户巨大,所以这也是一个重在的问题。对于程序的性能优化,最主要的是找到运行时间最长的函数,只有优化它,性能才有大幅度的提升,具体的方法我就不做详细的描述了。
总述
游戏测试是一个新的领域,它既有通用测试的特点,又有自己的特点。
