qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

JavaScript常用开发工具集合

 常规工具
  脚手架工具
  Yeoman:它旨在为开发者提供一系列健壮的工具、程序库和工作流,帮助开发者快速构建漂亮的Web应用。
  构建工具(自动)
  Grunt.js:生态强大,发展速度快,有大量可选插件;
  Gulp.js:流式项目构建工具;
  Browserify.js:Node.js模块,主要用于改写现有的CommonJS模块,使得浏览器端也可以使用这些模块;
  Uglify.js:JavaScript解析器、压缩工具和代码美化库。
  软件包管理工具
  Homebrew (Mac OS):Apple Mac OS下的软件安装工具;
  Apt:Debian、Ubuntu等系列Linux系统的软件包管理工具,可用来安装、删除、升级软件等;
  NPM:Node.js的官方软件包管理器;
  Bower:twitter的一个开源项目,用于web包管理。
  前端
  MVC框架
  Backbone.js:提Web开发的框架,为复杂的Javascript应用程序提供模型(models)、集合(collections)、视图(views)结构;
  Ember.js:可以创建功能丰富的Web应用程序,并提供一个标准的应用程序架构的JavaScript框架;
  Angular.js:一组用来开发Web页面的框架、模板以及数据绑定和丰富UI的组件,无需进行手工DOM操作,还允许为App扩展HTML类库。
  模板
  Handlebars.js:JavaScript页面模板库,可以为开发者提供必需的语义模板;
  Mustache.js:是Mustache模板系统的JavaScript实现,语法逻辑比较简单,适用于C++、Clojure、Erlang、Go、Java、JavaScript等语言;
  Jade:Node模板引擎,主要用于Node.js里的服务端模板;
  Haml-js:允许在JavaScript项目中使用Haml语法,与原生的Haml拥有差不多的功能;
  Eco:可以用来将CoffeeScript逻辑嵌入到标记中。
  测试
  Casper.js:CasperJS是一个为PhantomJS和SlimerJS准备的导航脚本及测试工具;
  Zombie.js:Zombie.js是一个轻量级的框架,可以在一个模拟的环境下测试客户端的 JavaScript 代码,且不需要浏览器的帮助。
 后端
  服务器
  Express:Node的web应用框架;
  Node:Node.js是构建于Chrome JavaScript运行时基础上的一个平台,可快速构建网络应用。
  数据库
  MongoDB:开源的文档存储数据库,也是领先的非关系型数据库;
  Postgresql:开源的对象-关系数据库服务器;
  SQL:结构化查询语言,可用来存取数据以及查询、更新和管理关系数据库系统。
  架构
  RESTful:目前流行的互联网软件架构,结构清晰、易于理解、方便扩展。
  测试
  Cucumber.js:采用受欢迎的行为驱动开发工具并将其应用到JavaScript堆栈中。
  Jasmine:行为驱动的开发测试框架,不依赖浏览器、DOM或任何其他JavaScript架构,较适合网站、Node.js项目或应用在任何可以运行JavaScript的地方。
  Mocha:运行在Node.js和浏览器之上,主要用于异步测试。
  Q-Unit:单元测试框架,常用于jQuery、jQuery UI和jQuery移动项目,也可以用于测试常规的JavaScript代码。
  断言库(Assertion Libraries)
  Chai:一个用于Node的BDD/TDD断言库(Assertion Libraries),可与任何JavaScript测试框架进行搭配。
  函数式编程工具
  Underscore.js:JavaScript库,提供了大量有用的函数编程工具,无需扩展任何内置对象;
  Lo-Dash:提供自定义、性能和一致性的JavaScript库。

posted @ 2014-08-15 09:53 顺其自然EVO 阅读(216) | 评论 (0)编辑 收藏

Android Robotium跨应用处理方法

  相信用过一段时间Robotium的同学一般都遇到过如下情况:界面跳转到被测程序外以后,Robotium就毫无对策了,这也是Instrumentation框架最致命的一个缺点;然而领导是不会管你这些很“充分”的理由的…..
  Ok,既然我们有这样的需求,还是想办法解决吧。调研了几天最终还是实现了一个曲线救国的方法:
  实现原理:编写一个程序A,用于接收CASE中发送的指定广播,当程序A接收到指定的广播后就会响应你注入的动作事件。
  准备工作
  熟悉Service 、BoradCastReceiver、input keyevent, 有不清楚的同学可以先百度下以上知识模块。
  具体实现:
  1、首先为了方便我们使用,我们可以设置为程序A为开机启动一个Service,该Service中注册一个BoardCastReceiver用于接收一个特定action的广播,设置一个IntentFilter:IntentFilter mIntentFilter=new IntentFilter(); mIntentFilter.addAction(“android.zered.action”);然后在BoardCastReceiver的OnReceive方法中使用Runtime.getRuntime.exec(cmdB)执行我们Case中发送过来的指令(input keyevent xx 当然也可以是其他的一些shell命令)。注意:关于设置程序开机启动,3.1以后Android系统对广播接收做了安全处理——未启动过的程序是不能接收广播的,当然我们还是有方法解决:即把该程序设置为系统级应用即可,然后把该程序push到system/app下重启手机;
  2、步骤1的完成已经为我们完成了一个命令执行端(可以理解为CS的server端),现在我们需要做的就是发送这个广播,发送广播的方法为context.sendbroadcast,所以我们在Case中就可以使用solo.getCurrentActivity.sendbroadcast发送广播;
  剩下的就是我们要把这个命令行cmdB封装到广播中,Intent intent=new Intent();intent.setAction(“android.zered.action”);intent.putExtra(TAG,cmdB);solo.getCurrentActivity.sendbroadcast(intent);
  Ok,这样以来一个带有命令行的广播就算是发送出去了。
  3、以上步骤完成以后,步骤1启动的程序A中的Service接收到步骤2发送的广播以后,就会执行我们发送的命令行指令cmdB了:Runtime.getRuntime.exec(intent.getStringExtra(TAG))
  以上就是Robotium跨应用的一种处理方法,欢迎大家拍砖。

posted @ 2014-08-15 09:53 顺其自然EVO 阅读(264) | 评论 (0)编辑 收藏

Oracle数据库迁移之物理迁移

  ORACLE数据库迁移有多种,今天先从物理迁移实验做起。
  物理迁移比较简单,但是要求两个库的版本必须一样,且必须事先记录要迁移的库的SID、归档模式、数据文件、日志文件、控制文件、参数文件和密码文件。
  迁移过程大致分为以下四步:
  1、用迁移的参数文件启库到nomount状态。
  数据库默认情况下是用$ORACLE_HOME/dbs/spfile<SID>.ora文件来启动的,如果要用pfile启动的话
  就制定pfile文件就可以启动,nomount状态也就是加载参数文件的过程,如果可以成功启动,那么就说明参数文件没有问题
  2、启到mount状态,mount状态是加载控制文件的过程。
  3、如果可以启到mount状态了,那么就可以进行开库操作了。
  4、开库成功之后,就说明迁移成功,可以看看数据丢失没,然后启动监听和配置文件等。
  下面进行试验:
  说明:如果两个库的目录建的一模一样的话,迁移相对简单,这里演示目录不一样的情况。
  准备工作
  查看原库的SID 、数据文件、控制文件、密码文件、参数文件、重做日志文件。
  这里就不贴过程了
  下面开始正式的步骤:
  1、用pfile起到nomount状态
SQL> startup nomount pfile='/u01/app/oracle/product/10.2.0/db_1/dbs/initorcl.ora'
ORACLE instance started.
Total System Global Area  432013312 bytes
Fixed Size                  2021344 bytes
Variable Size             121636896 bytes
Database Buffers          306184192 bytes
Redo Buffers              2170880 bytes
  成功之后赶紧用pfile生成spfile文件,方便后面对参数的修改
  2、起到mount状态
  SQL> alter database mount;
  Database altered.
  加载控制文件
  如果出现错误,就说明控制文件所在的路径和参数文件中的路径不一致,就要修改初始化参数文件中控制文件的参数,然后重新加载
  3、起到open状态
  SQL> alter database open;
  Database altered.
  这里出现错误的话,就是数据文件或其他文件找不到
  通过
  alter database rename file 'home/oracle/1.dbf' /home/oracle/oradata/1.dbf';
  来解决。
  4 迁移成功,开启监听
  SQL> select * from test;
  ID
  ----------
  1
  说明成功了

posted @ 2014-08-15 09:52 顺其自然EVO 阅读(297) | 评论 (0)编辑 收藏

如何提高测试用例设计的测试覆盖率

 说到测试用例的设计,我想每个有过测试经历的测试工程师都会认为很简单,不就是:按需求或概要设计,得到软件功能划分图,然后据此按每个功能,采用等价类划分、临界值、因果图等方法来设计用例就行了。
  但事实上撇开测试数据的设计不谈,仅就测试项来说,我们发现,对同一个项目,有经验的测试人员,在写用例或测试时总会有更多的测试考虑点,从而发现更多的问题;而有些测试人员测试用例的撰写却只有那么三板斧,表面看好象已经把页面所有信息的测试都考虑到了,实际上却还是遗漏了大量测试覆盖点,导致其测试出来的程序总是比较脆弱。
  究其原因,我觉得还是测试用例的撰写水平不到位,更确切地说是测试用例的覆盖度太低。说实话我认为系统测试用例真正做到100%覆盖是很难的。难道说按设计中的功能划分,每个功能都写到了这个用例就覆盖完整了?错,这还远远不够。因为我们知道还有大量的内部处理、转换、业务逻辑、相互影响的关系等都是需求或设计中所不会点明的。而这些一方面需要靠测试人员对项目本身的了解,另一方面要靠测试人员的经验,来一一找到这些隐藏点并予以测试,才能真正地保证我们的测试覆盖度。
  所以本文抛开具体的测试数据设计方法,主要从测试覆盖度的角度来介绍用例设计时,如何才能考虑地更周全,如何才能将隐藏的测试项一一找出,从而使我们的测试更全面更完整。
  想法虽然美好,可是毕竟每个测试的项目都是各不相同,针对不同项目我们的经验也会告诉给我们不同的想法,这些想法通常很感性,很难用严密的逻辑理论来把它升华。因此本文的内容仍是很简陋且不成熟,只是希望能以本文为砖,引起大家的思考,一起来补充完善,以使我们的测试用例设计水平不断提高。
  正文
  一、测试用例的切面设计
  1、功能点切面
  2、特定切面
  3、隐含切面
  (1)、后台功能
  (2)、完整业务流程的测试
  (3)、某种特定情况下的系统运行
  (4)、其它相关系统
  (5)、除功能测试外的其它测试类型
  二、详细用例的设计
  1、功能切面表面用例设计
  (1)、具体功能测试
  (2)、组合操作的测试
  (3)、GUI界面的测试
  (4)、数据初始化情况测试
  (5)、业务需求实现是否正确
  2、功能切面隐含测试项用例设计:
  (1)、数据完整性的测试
  (2)、后台的特殊处理
  (3)、功能业务之间的关联与转换
  (4)、从设计实现发掘测试点
  (5)、并发操作时的测试
  3、特定切面用例设计
  4、隐含切面用例设计
  (1)、无界面的后台功能
  (2)、与业务流相关的测试
  (3)、其它测试类型
  三、测试数据的设计
  一、测试用例的切面设计
  所谓测试切面设计,其实就是测试用例大项的划分。测试用例划分的经典方法是瀑布模型,也就是从上到下,逐渐细分,大模块包括小模块,小模块包括更小的模块。但仅仅如此是不够的,我们还要从更多的角度切入系统,从不同的角度把系统切分成一块一块的,来进行测试,从而确保测试大项的完整性。
  1、功能点切面
  这是最常见的切面,通常我们认为页面上的一个按钮就是一个功能点。然后我们可以根据功能的复杂程度,按每个功能;或一个功能点分多页;或多个功能点合成一页来进行用例的撰写。
  2、特定切面
  除此以外,还有一种特定切面的划分方法,也是用例撰写时经常会用到的。所谓的特定切面,就是忽略掉表面上的功能点,而关注测试对象的某一个面。比如我们的内部管理系统提供了销售录入导入、注册录入导入等功能,从菜单划分上对应了七八个功能点。但这些功能处理后台有个共同的处理项就是授权记录的生成,这时我们就可以把“授权记录生成”单独拿出来做一个测试项,而在其它测试项中涉及这一部分的用例就不必再一一撰写。此外象一些界面共通的操作用例单独写成一页,也是一种特定切面。所以如果说将用例按功能点划分是一种纵向划分法,那么特定切面就是从横向的角度分析所得到的切面。在普通功能点划分上再根据实际情况设计特定切面,可以使我们的用例阅读性、理解性、操作性更强。
  3、隐含切面
  这类用例是最容易被忽略的。它往往不是明显的某个功能项,可能是功能项后台的隐含处理,也可能是多个功能项之间的关联处理,甚至可能是在某种特定情形下的处理。这都需要测试人员通过对软件的学习了解,来进行挖掘。
  (1)、后台功能
  常见的如一些定时自动启动的服务;以及某种特定情况下自动执行的操作等。它们在界面上往往是不体现的,但许多在需求设计中还是会提到,也有一些比较细小的功能可能会被忽略,就需要测试人员根据对项目的了解程度来进行挖掘。所以说一个熟悉项目的和一个不熟悉的测试人员,写出来的用例就完全是两个层次的。
  (2)、完整业务流程的测试
  我们都知道测试用例的设计是从点、线、面三个层次去考虑的。完整的一个功能项是线,其中的某个按钮是点,多个相关功能结合成完整业务流就是面。从实际来看这类用例往往被我们忽略。
  事实上目前公司的软件本来都是业务型应用软件,将各种功能从业务流中切割出来单独写用例,肯定也会有涉及到整体流程的情况。若不加以区分,将细节与全局搅在一起,不仅思路混乱,也容易考虑不周。因此在系统测试阶段,建议用例设计要有分有合,针对具体功能的就只围着这个功能转:而在业务流程测试项中,再完全从整体的业务流角度出发去考虑用例,这样不仅不容易产生疏漏,用例阅读与执行也更清楚。
  (3)、某种特定情况下的系统运行
  这类用例的设计往往与系统实际业务情况密不可分。比如财务软件,通常需要在月尾一天、月头一天、年尾一天、年头一天,对所有相关功能中的日期处理进行测试;又比如WIN 2000环境开发测试的系统,要测试在98、XP、2003等操作系统下是否能运行自如;再有如存在大量动态图片视频等的网页,在普通网速下的展现速度等等。总之就是要尽可能从实际应用的角度出发考虑,来进行测试补充。
  (4)、其它相关系统
  即指在当前项目中直接使用的其它成果,包括公司自有的系统模块、组件、函数;以及购买或免费得到的一些功能组件。对这些内容需要预先与开发组长等讨论清楚,是否需要测试。若时间紧张或其它原因决定不测的,应在测试计划中说明。若需要测试的,则具体可根据实际情况来设计,可以是通过系统某个功能的测试来涉及,此时就不需要单独划分测试项;若相对比较独立的,也可以通过单独的测试项来对其专门进行测试。
  (5)、除功能测试外的其它测试类型
  包括可靠性、安全性、恢复性、配置安装测试等等,这些测试类型都是一个单独的测试项。
  所谓好的开始是成功的一半,保证测试项划分的完整、合理、正确,会直接影响到本次测试的成效。通常建议该阶段工作要花1-2天的时间来考虑,并要在测试过程中随着对软件的深入了解,不断进行调整补充。可千万不要认为把分析设计中的功能模型图搬搬过来就可以了。
  二、详细用例的设计
  划分好了测试项,接着就是针对各个测试项,考虑具体的测试用例了。根据测试项的特点,测试用例的设计角度也有所不同。下面我们就来看看通常的功能点测试用例,该从哪些角度出发来进行设计:
  1、功能切面表面用例设计
  (1)、具体功能测试
  根据需求分析设计,按页面提供的各个功能项,采用黑盒测试的各种方法,设计用例。比如页面提供了增、删、改、查功能,那么这四个功能是否正确实现就是我要验证的。这是最简单、最基本,同时也是必须的测试用例,通常我们的编码人员自测也就是做到这个程度。^_^
  (2)、组合操作的测试
  这是从上一角度扩展出来的,相对而言也是编码人员不会去测试的,所以需要测试人员多作考虑。
  所谓组合操作测试,也就是选择某几个操作项,按一定的顺序进行操作,验证系统不会出现意外错误。当然要将所有功能项排列组合一遍来测试不仅不必要,也是不可能的。所以具体要将哪些功能项进行结合,要按怎样的步骤来操作,还是需要测试人员根据实际情况来作设计(所以说在IT业人才就是一切呀,呵呵:)。
  一般来说我们会考虑功能项之间的数据是否会存在关联,若有就需要考虑这种组合了。常见的如查询功能,需要将各条件逐一累加进行测试;增完的数据能否改,改完能否删,删完能否再增,这之间能否查询到正确结果;按钮的连续多次点击会否出现异常;有严格前后顺序要求的几个操作,尝试颠倒顺序去操作,系统能否控制等等。
  不仅在某功能内部,扩展到有关联的多个功能项之间,同样有组合操作测试的存在。如申报完了能才反馈;如申报成功或失败后再尝试申报等。当然对于这类用例既可以写到某个功能切面中,也可以单独写到完整业务流程的切面中,这就取决于可能涉及用例的数量了,若关系比较复杂,当然是单独写比较好;若也就是三五个用例数,那就直接在某个功能的用例中补充好了。
  (3)、GUI界面的测试
  这类测试是测试人员的强项,具体测试项目如限长、非法输入等等,就不必赘述了。要提醒的是在测试时,一定要从实际使用者的操作习惯出发。要知道界面原型所能确定的也只是页面的摆放显示,而实际操作时的控制实现仍是编码人员自行实现的,即使有编码指南,其所及范围也是十分有限。而许多编码人员在用户操作方便性上的考虑往往差强人意。所以测试人员就必须要把好这一关。
  (4)、数据初始化情况测试
  不该为空的数据是否有校验;该有默认值的数据默认值是否正确;引用其它功能生成的数据,是否会实时刷新;页面关闭或系统重启后,数据的初始化设置等都是这类用例。
  (5)、业务需求实现是否正确
  这类问题往往是由于我们的需求说明欠详细,而编码人员的需求了解程度又较低造成。作为测试人员自然要对需求进行深刻研究,来对软件实现进行把关。这里常见的一些关注点有:
  数据的长度、类型控制是否合理(比如控制纳税人识别号只能为数字,但实际业务中是会有字母出现的);
  业务逻辑控制是否合理(比如某数据项不提供修改,但实际业务中该数据项经常会需要改动);
  提供的实现方式是否合理(比如只在某一页面提供某数据的获取功能,但根据业务划分有些人员不能操作此页面,却必须要能看到该数据);
  所做的数据控制是否合理(比如必须在A功能中新增数据,然后才能在B功能中操作,但实际业务中有可能会出现相反操作);
  所做的数据控制是否完整(如授权的方式有普通按月、有买断、有按数量控制,那么当同一企业尝试同时存在以上几种授权方式时,系统是否能有必要的控制);
  还有其它一些操作细节上的满足(如业务上需要批量操作的数据有否提供批量操作功能、导入失败的结果文件是否能修改后直接再导入等)。
  对于不满足的需求,经开发组长、需求经理等确认不作修改的,就要作为软件的缺限或限制在测试报告中进行说明民。
  2、功能切面隐含测试项用例设计:
  (1)、数据完整性的测试
  当某数据被其它功能引用;或当前功能要引用其它来源的数据,就会涉及到数据完整性的测试。最常见的如被引用的数据删除了,或关键字被修改了,引用的数据会否出错;两个途径进入的数据会否冲突或重复;此外还有因为相关的几个功能由不同人员编码,从而导致彼此的控制不一致,如A功能进入的数据在可允许的极端情况下,到B功能中引用会否异常(最常见如用户名录入时允许长度10,但引用到某个单子填写时允许长度是8,此时就会异常了)。
  (2)、后台的特殊处理
  是指某功能除了表面所见以外的程序处理。比如订单录入,表面所见的就是订单的保存,但后台还会有重复数据的判断、非法数据的处理、业务逻辑上冲突情况的处理以及其它种种根据需求设计所特有的处理。又比如备份功能,在备份前可能有数据的清空、备份目录的清空、备份目标是否存在的校验、备份文件重复时的处理等等。类似这些在分析设计中就未必会写全了,还是要测试人员多花心思去思考挖掘。
  (3)、功能业务之间的关联与转换
  相关联的几个功能之间数据的传递,会否产生影响。比如新增录入的某种特殊字符,要查询时会引起查询SQL语句异常;又如某下载文件名中存在中文等字符,下载时由于编码问题导致乱码的出现;再有报表填写时到小数点后四位,生成报文时会不会被忽略成两位了等等。象这种问题,通常只能是在每个功能设计用例时,尽量保证用例中的数据能涉及到允许范围的各种情况,即充分运用等价类划分+边界值的方法设计出各种“稀奇古怪”的数据,并需验证这些数据从头流到尾,都还是能保持其正确性,而不仅仅是在当前功能中正确。
  (4)、从设计实现发掘测试点
  这个就是我们测试中最难捉的BUG了,它往往是由编码人员自己在编码时创造出来的,连设计人员都不会知道。
  比如内部管理系统中,正常的产品,其类别通常是2位数字;如果是模块,其类别就以产品代码来取代。这时如何来判断该产品是模块呢?最保险的当然是校验其产品类别字段的值能否在产品表中找到;也有比较简单的方法就是直接判断类别代码大于2位还是小于等于2位。此时若能确切知道采用的是哪种实现方法,就可以直接找到其漏洞所在。比如采用后一种方法,当产品类别长度变化时,明显系统会出错。那么即使确认该实现方式不改,测试人员也应将其作为限制写入测试报告,。让大家知道这个产品类别长度是不能随意变化的。
  而让人郁闷的是,类似这样的实现,有太多的编码人员都是随性处理的,它们细而隐蔽,在系统数据正常情况下根本不会被发现;而在漫漫的软件使用道路中,由于需求变更等原因对原有一些设计做维护变化,这种问题就会突然暴发出来让人措不及防。所以要杜绝这类漏洞,除了测试人员要做土拨鼠,不停地对软件各功能的实现细节进行挖掘外,也要多给编码人员灌输完美实现的理念,多用复杂但抗压性高的代码,来替代简单但依赖性强的代码。
  (5)、并发操作时的测试
  即两个或多个用户同时操作同一功能时,会否引起数据的混乱。通常在C/S结构下,如果有同时操作的可能,是需要作此测试的;而在B/S结构下由于其特殊性,此问题通常难以解决。除非就是某用户一旦使用过某功能后,在一定时间内锁定不允许再用,但这也会带来实际应用中的不便,所以除非是特别核心的数据,一般我们也不会去做此控制,当然对于可能出现的并发冲突也就作为系统的限制进行遗留了。
  3、特定切面用例设计
  所谓特定切面,其实就是从另一个角度切割出来的用例面,所以具体的用例撰写方式其实与功能切面是一致的。
  4、隐含切面用例设计
  隐含切面分以下几种情况:
  (1)、无界面的后台功能
  对这类测试项,需要通过参数设置、代码调用等方式来实现测试,但具体的测试设计其实与普通功能测试并无二致。这里要注意,因为测试时往往前台、后台是分开来分别进行的,而实际运行时两者很可能是交集的,所以测试时要多注意后台功能的执行与前台的一些功能执行会否产生冲突?比如后台有个文件搬运的服务,那有没有可能在前台文件生成过程中,后台执行文件搬运了?若有可能就要注意会否出现问题了。
  (2)、与业务流相关的测试
  这类测试用例的设计,就要从完整业务角度来设计数据了。从理论上来讲,应该要将各个功能可能出现的各种数据排列组合到一起,按业务流程逐一进行测试。但实际上我们不可能去做全覆盖。所以设计这类用例时,最好有一张草稿,将所有相关功能按业务流程逐一列示,然后再将每个功能可能出现的特定数据一一标上,最后将图中最可能出现的、最可能出错的、最核心的数据取出来,分别组合成一个个完整的业务数据用例,来进行测试。这样就可以按清晰的思路,找出最实用、最有效的测试数据。
  (3)、其它测试类型
  这一类的测试通常都有其特定的方法。如要测可靠性就准备大量数据不停地执行;要测安全性就考虑数据的加密、数据的传输、数据的破坏;恢复性一般从网络、电源方面着手;配置安装则根据系统可支持的配置,搭建相应环境进行功能验证,此处的验证也要掌握技巧,即要多测试那些涉及到:数据库读写、磁盘文件读写、文件上传下载、文件加解密、数据统计、图表展现、打印等方面的功能。
  三、测试数据的设计
  每一个测试思路最终都要转化成具体的数据才能来执行。关于测试数据设计的方法也不外乎那几种,就不再赘述了。此处单就一些经常易犯的错误,提出一些注意点,作为用例数据设计时的参考:
  1、尽量避免可能出现歧义测试结果的数据:即你设计的数据必须能唯一正确地反映出你所希望测试的结果。比如一组测试数据,有可能得到结果A或结果B,此时单用此数据来测试预期结果为A的用例,那明显就产生了歧义。
  2、对于不便具体列示的数据,则必须详细描述其各项特性:有时我们在设计用例时为节约时间,不一定要到具体的一个数值,这也是允许的,但前提是你必须要详细描述清楚你要测试的数据特性。比如数据库字段限长20,要测试超长数据时,可以描述为:尝试输入长度为21位的半角英文字符;尝试输入长度为19位的半角英文字符,然后切换到中文全角再输入一位全角字符等。千万不能写成:尝试输入超长字符,因为这只能是测试方案,作为方案是可以这样写,但到用例阶段,必须要是具体的、明确的、可操作的。
  3、测试数据的设计必须有明确目的性:即测试数据是从测试方案衍生而来的。如上例测试方案是测超长字符输入控制,所以测试数据就要根据具体字段长度来录入超长数据,如果一味录入长15位、长16位的数据那就没意义了。好的测试数据是可以同时针对多个测试方案的,此时可以在用例边注明一下该数据的测试目的,因为随着时间推移,对着具体的数据你也许会忘了它到底是测什么的,而这对你最后总结测试,查验测试覆盖率是非常不利的,所以随时记下你的思路想法吧,好记性不如烂笔头。
  4、测试数据可省略描述:测试数据描述以能让人看懂为准则。所以写用例时当碰到连续几个用例,仅某几个关键数据值改动,其余均是一样的情况下,不必每个用例都要重复描述所有数据,可以在第一个用例描述完整之后,其余用例中仅列示不同的数据,并标明其余数据同上第X个用例,即可。这样测试时仍能复原测试数据,且该用例的测试目的一眼就明,增加了用例的清晰性。
  至些,我根据测试用例设计的顺序,从测试数据的切面设计(即测试项划分),到详细测试用例设计,再到测试数据设计三个层面,逐一介绍了如何来提高测试用例的覆盖度。因为具体项目中的具体情况太多,以上叙述的内容也只能是管窥蠡测。至于其中的疏漏错误之处应也难免,只希望各位阅后能打开思路,从自己多年的测试经验中多总结、提炼出一些想法思路,进一步补充完善这个文档,使大家的测试用例设计能力都能进一步提升。

posted @ 2014-08-15 09:27 顺其自然EVO 阅读(222) | 评论 (0)编辑 收藏

Oracle数据库体系结构解析

  Oracle 数据库体系结构图 如下图所示,
  纵观上图可知,Oracle数据库服务器大致分为两个主要部分 既1.Oracle instance (数据库实例 上半部分)2.database (数据库 下半部分)。
  用户不能直接连接到数据库,而是用户先发出一个用户进程, 用户进程和Oracle服务器发出的服务器进程交互,然后服务器进程再和实例交互,最后实例和底层数据库交互,从而实现用户和数据库的交互。具体过程看下图:
  下面详述体系结构中各个组成部分的具体功能和特点
  1.首先先有的整体的认识:
  oracle 服务器=实例+数据库
  实例=SGA(实例内存)+后台进程
  内存=SGA+PGA
  SGA=database buffer cache (数据库高速缓存区缓存)+share pool +redo log buffer
  2.实例内存SGA结构:前三个是必选的,其余是可选的。
  1)database buffer cache(数据库高速缓存区缓存) :是用来存放执行SQL工作区域 (1)存储从数据文件中获得的数据块的镜像(2)当获取和更新数据的时候能够大幅度提高性能,因为数据库块的镜像会保存一段时间,等下次再执行有关这个块的操作时,可直接在缓存区操作(3)能够动态调整大小,也可以对其进行自动管理。
  2)Redo log buffer (在线日志缓冲区): ()记录所有数据库的块的改变,主要用于恢复,大小由log_buffer 决定, 在对数据库块进行操作之前,会把所做的所有操作记录这里。
  3)share pool (共享池):包括library cache (库高速缓冲区)和database dictionary cache(数据字典缓存)  ,前者主要存储最近使用的SQL和pl/sql 语句的信息(存一次 多次使用,防止硬解析,) 后者主要存储最近使用的定义,如表、索引、列、用户权限、和其他数据库对象。
  4)Large pool :  是系统全局区的一个可选的部分,是共享服务器的会话内存,以减轻在共享池中的负担,可动态的改变大小,也可以自动管理。
  5)Java pool:   java 命令的分析,可动态的改变大小,也可以自动管理
  6)Stream pool : 流相关的数据在流池中,提高缓存效果。
  3.接下来介绍实例后台进程:
  1) pmon (进程检测进程) :当会话异常终止时 清除失败的进程 包括 回滚事务、释放锁、动态注册监听器,
  2) Smon (系统检测进程):实例恢复(前滚所有重做日志中的改变、回滚没有提交的事务),释放临时表空间。
  3) DBWn(数据写进程): 将数据库高速缓存区缓存中的脏块,刷新到磁盘数据文件中,  写的条件:1,发生检查点2,脏缓存到达极限值(1/4)、没有可用的缓存区时。
  4) LGWR(日志写进程)将redo log buffer 中的redo 刷新到磁盘日志文件中,  写的条件:1,commit 的时候,2.达到1/3满时,3.大小达到1M时,4.每搁三秒 5.在DBWR进程写数据之前。
  5) CKPT (检查点进程) : 给dbwn 信号,使它开始写脏块。更新数据文件头和控制文件,(就是把scn号更新为最新的)3秒一次。  常说的一致性 要保证三个scn 号一致,包括数据文件头的scn号,control files 记录数据文件头的scn号,control files 记录的总的scn号。检查点进程 触发的越快,DBWR 写的就越快,这样内存中的缓存区脏块就越少,进而恢复实例所用的时间就会越少,但是频繁的I/O导致性能下降,所以性能和速度是矛盾的;
  6) ARCn (归档进程):将联机重做日志文件归档到(也可以理解为复制)归档日志文件 ,如果开启了归档模式  重做日志文件 一般分为两个组,这两组是循环复写的,一个组用来记录对数据库的修改,另一组进行归档。但是如果记录修改的那组已经写满,这样本来该再去写另一组,但是另一组还没有完成归档,这就会出问题,数据库夯住了。。

posted @ 2014-08-14 09:33 顺其自然EVO 阅读(179) | 评论 (0)编辑 收藏

Linux系统查看内存使用率

Linux下看内存和CPU使用率一般都用top命令,但是实际在用的时候,用top查看出来的内存占用率都非常高,如:
  Mem:   4086496k total, 4034428k used,    52068k free,   112620k buffers
  Swap: 4192956k total,   799952k used, 3393004k free, 1831700k cached
  top –M看更直观,以M为单位
  接近98.7%,而实际上的应用程序占用的内存往往并没这么多,
  PID USER      PR NI VIRT RES SHR S %CPU %MEM    TIME+ COMMAND
  25801 sybase    15   0 2648m 806m 805m S 1.0 20.2 27:56.96 dataserver
  12084 oracle    16   0 1294m 741m 719m S 0.0 18.6   0:13.50 oracle
  27576 xugy      25   0 986m 210m 1040 S 1.0 5.3 28:51.24 cti
  25587 yaoyang   17   0 1206m 162m 3792 S 0.0 4.1   9:21.14 java
  看%MEM这列的数字,按内存排序后,把前几名加起来,撑死了才不过55%,那剩下的内存都干嘛用了?
  一般的解释是Linux系统下有一种思想,内存不用白不用,占用了就不释放,听上去有点道理,但如果我一定要知道应用程序还能有多少内存可用呢?
  仔细看top关于内存的显示输出,有两个数据buffers和cached,在Linux系统下的buffer指的是磁盘写缓存,而cache则指的是磁盘读缓存。
  (A buffer is something that has yet to be "written" to disk.
  A cache is something that has been "read" from the disk and stored for later use.)
  而这两块是为了提高系统效率而分配的内存,在内存富余的时候,操作系统将空闲内存利用起来,而有内存需求时,系统会释放这部分的内存供应用程序使用。
  这样,真正应用程序可用的内存就是free+buffer+cache,上面的例子就是:
  52068k + 112620k + 1831700k = 1996388k
  而已用内存则是used-buffer-cache,上面的例子为:
  4034428k - 112620k - 1831700k = 2090108k
  Linux下查看内存还有一个更方便的命令,free:
  $ free
  total       used       free     shared    buffers     cached
  Mem:       4086496    4034044      52452          0     112756    1831564
  -/+ buffers/cache:    2089724    1996772
  Swap:      4192956     799952    3393004
  Mem:这列就是用top命令看到的内存使用情况,而-/+buffers/cache这列就是我们刚刚做的计算结果,used-buffer-cache/free+buffer+cache
  也可以加-m或者-g参数查看按MB或者GB换算的结果。
  $ free -m
  total       used       free     shared    buffers     cached
  Mem:          3990       3906         83          0         90       1786
  -/+ buffers/cache:       2029       1961
  Swap:         4094        781       3312
  这样,真正应用程序的内存使用量就可以得出来了,上面的例子中内存占用率为51.1%。
  例如:
  # free -m
  total       used       free     shared    buffers     cached
  Mem:               4229       2834       1395          0         62       2548
  -/+ buffers/cache:                223        4006    //物理内存使用223M,剩余4006M
  Swap:               8001       0         8001

posted @ 2014-08-14 09:33 顺其自然EVO 阅读(3381) | 评论 (0)编辑 收藏

一个例子理解java面向对象的机制

//定义Gun类
public abstract class Gun {
protected String name;
// 带参数的构造方法,特殊的方法,名字必须与类名相同
public Gun() {
public Gun(String name) {
this.name = name;
// 构造抽象方法,并在子类中继承和定义。
abstract void sound();
public String getName() {
return name;
public void setName(String name) {
this.name = name;
//Carbine继承自Gun
public class Carbine extends Gun {
//带参数的构造方法,特殊的方法,名字必须与类名相同
public Carbine(String name) {
this.name = name;
//Gun类下不同的子类拥有同名的sound()方法,但是内容不同,在调用sound()方法时会根据具体的Gun而自动调用相应的方法。
//这用到了Java的多态性。
void sound() http://www.huiyi8.com/jiaoben/
// TODO Auto-generated method stub
System.out.println("DaDaDa!"); javascript特效
//Rifle继承自Gun
public class Rifle extends Gun {
//带参数的构造方法,是特殊的方法,名字必须与类名相同
public Rifle(String name) {
this.name = name;
//Gun类下不同的子类拥有同名的sound()方法,但是内容不同,在调用sound()方法时会根据具体的Gun而自动调用相应的方法。
//这用到了Java的多态性。
void sound() {
// TODO Auto-generated method stub
System.out.println("Peng! Peng! Peng!");
//定义Person类
public class Person {
private String name;
public String getName() {
return name;
public void setName(String name) {
this.name = name;
// 体现多态性。
public void shoot(Person p, Gun g) {
System.out.println(this.name + " shoot\t" + p.getName() + " using a "
+ g.getName());
g.sound();
//在main()函数中测试
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Person p1 = new Person();
Person p2 = new Person();
p1.setName("XiaoWang");
p2.setName("XiaoLi");
Rifle r = new Rifle("rifle");
Carbine c = new Carbine("carbine");
// 将方法的调用和实现分离,已达到封装的效果。
p1.shoot(p2, r);
p1.shoot(p2, c);

posted @ 2014-08-14 09:30 顺其自然EVO 阅读(186) | 评论 (0)编辑 收藏

敏捷项目中的安全需求管理

软件开发初期处理安全需求是防止安全问题最经济的方式。大多数安全需求都属于非功能性需求(Non-Functional Requirements ,NFRs)。很多从业者发现,在敏捷项目中处理安全和其他NFR非常具有挑战性。原因有二:
  匹配NFR和特性驱动的用户故事需要付出很大努力;
  安全控制常因缺少可见度而被忽视。敏捷过程容易让团队不自觉地侧重于那些可以直观改善客户体验 的新功能开发或缺陷修复。
  在本文中,我们会探讨以上两个问题。
  在用户故事中处理NFR
  敏捷专家们提出过一些方法,用以定义用户故事驱动的开发过程中的NFR。Mike Cohn在他的文章中讨论了评论者们提出的一些有趣的建议。Scott Ambler就该主题写了一系列文章,旨在证明并非所有的NFR都可以独立存在于用户故事中。而Dean Leffingwell可以说在这方面做了最深入的研究,他在自己的著作《敏捷软件需求》中花了整整一章探讨该主题。这些专家中大部分人都认为,NFR大致可以分成两类:
  非功能性用户故事:以用户故事的形式展现的可测试功能块。这些用户故事中的参与者(Actor)可能是内部IT人员。例如:“作为安全分析师,我希望系统能抑制不成功的身份认证尝试,这样应用程序在面对暴力破解时不至于太过脆弱”。
  约束:这是个跨领域的问题,常常涉及多个用户故事。我们可以将它看作是对所有相关开发工作收取“课税”。例如:开发Web应用时,要求所有开发者对Http表单中的字段进行数据校验即为一种约束。
  处理第一类NFR很简单:创建一系列的NFR用户故事,将它们加入某种工作序列,例如Product Backlog。
  NFR约束的挑战:
  然而处理第二类NFR则困难很多。敏捷专家们对此提出过一些解决办法,包括:
  在特定的用户故事中添加恰当的约束作为验收标准
  在某个中央知识库——例如,贴在墙上或者发表在wiki上的一份文件——中维护包含所有约束的列表。
  但无论哪个方法都无法解决的问题是,如何针对特定的用户故事选择适用的约束。而且,使用SD Elements进行安全需求匹配的经验表明,要将这些技术限定在一定范围之内很困难。下面这个列表是标准Web应用需要面对的安全约束中的一部分,我们以此为例:
  在SQL语句中以变量绑定的方式阻止SQL注入
  对来自客户端的只读数据进行完整性验证,以防止参数篡改
  避开存在于HTML、HTML属性、CSS以及JavaScript中的不可信数据,从而防止跨站点脚本攻击)(XSS)
  避免客户端JavaScript中基于DOM的XSS
  使用安全的算法以避免整型溢出
  不接受外部重定向以防止自由重定向攻击
  授权给受保护的页面,以防止权限提升攻击)
  使用防止跨站请求伪造(CSRF)的令牌
  验证输入
  尽量使用正则表达式,因为它对于拒绝服务攻击有较强的抵抗力。
  为高价值的事务实现事务身份认证
  不要硬编码密码
  该列表列举的可能只是程序员在实现用户故事时需要考虑的安全约束中的一小部分。若将需要遵循的法规标准——诸如支付卡行业数据安全标准(PCI DSS)之类——考虑在内,约束还要增加不少。如果你开始添加其他NFR约束,例如可访问性,约束列表会快速增长,转眼间就会超过程序员的承受范围。一旦列表变得臃肿,我们的经验是,程序员往往会将它全部忽略,仅根据自己的记忆来应用NFR约束。而在很多不断专业化的领域——例如应用安全——NFR的数量不断增长,这给程序员的记忆力造成了沉重的认知负担。因此,如何使用静态分析技术侦测代码中违背NFR约束之处就成了关注重点。研究表明,静态分析可以侦测出的可预防缺陷最多不超过总数的40%,也就是说仍有大量的约束漏网,包括特定领域的安全控制,更别说在缺乏定制的情况下辨别静态分析产生的“假阳性”结果也不是那么简单。
  应对NFR约束的挑战
  为了解决NFR约束过多的问题,我们需要做到以下四点:
  按优先级排序:与用户故事和缺陷一样,NFR约束也应拥有不同的优先级,例如:相较于避开HTML中的不可信数据以防止持续的跨站脚本攻击,对HTTP响应头中的不可信数据进行编码或校验以防止HTTP响应拆分攻击就不那么重要。因此我们假定程序员通常没有足够的时间处理所有约束,然后我们提供一种机制为如何定义约束的相对优先级提供建议。之所以说“建议”,是因为优先级有可能随着具体情况的变化而变化,程序员需要自己作出判断——对于他们的特定代码,哪种相对优先级是适用的。你可以选用简单的优先级设置,如“高、中、低”,也可以使用数字范围,如1-10。
  过滤:使用简单的标准常常就可以为特定的用户故事移除大量的NFR约束。举例来说,假如你正在实现的用户故事与表现层无关,那么就可以安全地忽略大量表现层相关的约束。使用标签系统或者简单的Excel过滤器,就可以为特定的用户故事削减约束数量。以下是一些Web应用相关的安全性约束过滤器的范例:
  用户故事是否涉及用户输入;
  用户故事是否涉及保密数据,如密码、信用卡信息以及非公开的财务数据;
  用户故事是否返回一个全新或修正过的用户输出,例如一个网页;
  用户故事是否与数据库进行交互;
  用户故事是否会暴露或使用来自RESTful 或SOAP API调用的数据;
  用户故事是否会访问受保护的数据(例如,不是所有用户都能查看或修改的数据)。
  情境(Context):程序员在写代码或定义任务单(tickets)/ 用户故事的时候更容易记起并应用约束。理想情况下,如果把约束列表内嵌入IDE或任务单系统,那么程序员就可以在编码时获取相关的约束。既然现在很多IDE都支持内嵌的Web浏览器,那么使用轻量级的网站或者SharePoint站点就可以实现这个目标。
  框架:框架可以大幅减少约束产生的“税收”。例如,像 Django这样的框架自带了CSRF防护,这意味着程序员可以安全地忽略该约束,除非他们主动绕过这个内建的功能。根据我们的经验,多数大型的应用软件都会采用某种形式的定制框架,这些框架可以无缝处理最高优先级的约束。虽然这样的框架定制可能需要较高的先期投入,但如果你将约束看成一种基于用户故事的“税收”,那么减少约束数量就相当于永久性的降低了“税率”。
  验证
  虽然主动处理NFR很重要,但仍有必要进行验证。如果你有手动代码审查(Code Review)的经验,就可以检查用户故事中作为验收标准出现的NFR。然而,如果仅使用手动代码审查,很多约束的验证将是非常棘手或者繁重的。静态分析工具则可以自动检查编码标准的遵守情况,其中一些产品特别关注安全方面。将你的静态分析工具与持续集成过程整合在一起,可以帮助你始终遵守编码标准。但也务必注意,不要一味依赖于代码审查。防范特定领域缺陷——如HTTP参数篡改——的NFR要求对背后的业务领域有深刻的理解。将手动验证与针对特定攻击的自动测试结合起来,可以帮助我们建立一套对于特定领域缺陷拥有更强抵抗力的系统。
  可见度
  难以将安全需求集成进敏捷项目的另一方面原因是安全需求通常缺乏可见度。面向客户的会议,如Scrum的Sprint评审会议),容易使开发人员产生一种固有的倾向,即实现用户故事或修复缺陷时倾向于那些能直接改善用户体验的故事或缺陷。一部分非功能属性,例如易用性和性能,对于系统的使用体验有具体的影响,因此也比较容易向客户展示。而另外一些——如安全性——却很难在Sprint评审会议上给客户留下很好的印象。实际上,某些安全特性,如账号封锁(Account Lockout),可能给客户体验带来相当负面的影响。大多数安全特性对系统的影响,普通用户很难察觉。因此,安全性NFR是不可见的,它们必须和可见度更好的特性竞争,以夺得宝贵的开发周期。在软件开发初期,准确的说在程序员应该构建安全特性的时候,处理这些“隐形”需求的机会成本会特别高。
  让安全特性可见
  对于敏捷团队来说,没有“银弹”能让安全需求在开发伊始就拥有最高优先级。但有一些方法可以让安全NFR对客户和/或PO可见。
  图形化安全用户故事:如果你在应用程序安全方面足够专业,就可以针对已知的安全弱点创建一套全面的安全控制。然后将它们与NFR用户故事匹配起来,并绘制简单的图形,用以说明系统中已实现的和未实现的安全用户故事数量。这个图可以放在大型可视图表中。
  图1:安全用户故事图
  当然,这个图没必要局限于安全用户故事,你可以将其他重要的NFR囊括进来。实际上,你可以使用故事点(Story Point)取代用户故事数量,从而更准确的反映工作量。另外,你有可能希望图中只记录那些针对高风险安全问题的、拥有最高优先级的用户故事或控制。每完成一个故事,“已完成”数量都会增加,客户也会籍由此图直观地了解项目的进度。
  展示可利用性(exploitability):没有什么比可利用性展示更能让人们理解一个安全漏洞的各个方面了。这是安全性渗透测试和漏洞评估的主要区别。你可以展示在上一版本的应用中如何成功地利用了漏洞,而在新的版本中却没办法这么做了。然后你可以从对业务和/或客户影响的角度解释漏洞的方方面面。这非常有利于解释为什么在安全控制上花的时间是合理的。
  结论
  主动处理NFR,特别是安全特性,在敏捷环境中非常重要。不少专家对于如何处理此类需求——特别是当它们与创建用户故事相关时——给出了建议。全面地处理约束是个相当大的挑战。记住本文讨论的提议,你可以极大地增加维护一系列约束的价值。即使不能完全做到以上所提的四点内容以改善对约束的管理,但从长远来看,任何一点改进都能带来很高的回报。进行验证能保证团队始终遵守NFR。最后,提高安全特性的可见度,可以让你证明用在NFR上的时间是合理的,就算它们对系统的改善不能反映到用户体验上。

posted @ 2014-08-14 09:28 顺其自然EVO 阅读(204) | 评论 (0)编辑 收藏

质量管理的几个感想

 最近在跟进某个项目的质量管理,过程中有一些感受,总结下以便回顾。
  第一,质量管理的重要性必须得到高层的支持
  和之前ERP系统实施一样,没有得到高层全力支持的项目很容易中途流产。在项目管理体系中,就体现为干系人的管理。
  前期从每个项目干系人的立场和利益考虑,去协调干系人之间的关系是很惨重要的。这次的项目上来看,没有高层的介入,使得项目组负责人和质量管理组负责人之间并没有达成共识,在沟通交流上的成本代价很高。
  第二,质量管理组和项目组之间必须达成相同的标准认知
  质量管理采用的标准必须和项目组之间达成一致。在项目开始之前应该有专门的流程来保证。在项目中期去讨论和修改标准会给项目带来巨大的风险,同样,没有在前期达成共识,项目组合质量管理组之间也会有很大的沟通成本产生。
  第三,质量标准一定要细化到可操作
  在制定标准细节时,避免产生模棱两可的写法。没有可操作性的标准还不如不要这样的标准。
  第四,和客户之间确定和质量标准
  没有100%的质量标准,我们也不可能不计成本的去实现100%的质量。所以,合理权衡成本,质量和时间,制定满足客户须有的项目质量标准是很讲究的。

posted @ 2014-08-14 09:26 顺其自然EVO 阅读(174) | 评论 (0)编辑 收藏

使用TestNG-xslt美化测试报告

 用TestNG测试后,自动会生成html的测试报告,不过相信大家都有感觉,自动生成的测试报告太难看了,所以我们又用了ReportNG来美化它。在 这里给大家再介绍一下比reportNG还要稍稍美观一点的reporting tool: testNG-xslt.
  其实testNG-xslt就是把testNG自动生成的测试报告testng-results.xml进行了一个转换,把它的html输出报告变得更漂亮 而已。因此用法也很简单:
  1. 在官方网站上下载testNG-xslt ,http://testng-xslt.googlecode.com/files/testng-xslt-1.1.zip
  2. 解压后把saxon-8.7.jar放到project的lib目录下(在bulid路径里也把这个lib加上)
  3. 然后再把/src/main/resources/testng-results.xsl放到你的 test-output 目录下
  4. 在测试项目的根目录下创建一个简单的build.xml, 如下:
<?xml version="1.0" encoding="UTF-8"?>
<project name= "testTng" basedir= "." default="transform">
<property name= "lib.dir" value= "lib" />
<path id= "test.classpath" >
<!-- adding the saxon jar to your classpath -->
<fileset dir= "${lib.dir}" includes= "*.jar" />
</path>
<target name= "transform" >
<xslt in= "G:/eclipse3.7/workspace/testTng/test-output/testng-results.xml" style= "G:/eclipse3.7/workspace/testTng/test-output/testng-results.xsl"
out= "G:\eclipse3.7\workspace\testTng\test-output\index1.html " >
<!-- you need to specify the directory here again -->
<param name= "testNgXslt.outputDir" expression= "G:\eclipse3.7\workspace\testTng\test-output" />
<classpath refid= "test.classpath" />
</xslt>
</target>
</project>
  5.最后用 ant 运行这个 xml 就会在test-output 目录下生成 index1.html,打开它就是测试报告了。
  转换前的测试报告:
  转换后的测试报告(是不是美观很多呢):

posted @ 2014-08-14 09:25 顺其自然EVO 阅读(1813) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 65 66 67 68 69 70 71 72 73 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜