qileilove

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

软件测试向敏捷要什么?

  敏捷软件开发与其他软件开发方法学最大的区别,在于敏捷是承认并拥抱变化的。为了这样的变化,敏捷的不同方法,比如极限编程、Scrum引入不同的技术实践和流程,像持续集成、测试驱动开发以及短迭代周期等,来确保即使在需求的快速变化下,也能保证交付的软件总是满足用户的需求,是高质量的价值交付。

  从敏捷软件开发宣言来看,并没有涉及测试的内容,更不用提为QA即测试人员提供指导性的建议。就是以极限编程的14个推荐实践来看,表面上对于测试的提及也只是验收测试,甚至没有敏捷测试这个概念。这样让很多人一度认为敏捷软件开发是不是之以程序开发为导向的,是不是我们测试人员能从敏捷获得的直接支持少之又少,我们是不是被遗忘的一个种群?

  答案必然是否定的。还以极限编程为例,除了验收测试以外,极限编程提及的完整团队、用户故事、短交付周期、持续集成等实践,都在从不同的维度对于测试工作的流程和方式甚至对它思考的角度提出了变化的要求。

  完整团队从文化氛围和组织结构上明显区别与过往的测试人员参与感,测试人员不再是对软件系统质量负责的唯一角色,对质量负责的是全体团队成员的职责。用户故事改变以前对于软件系统功能和模块的划分,而是从交付的独立价值出发,改变了测试人员对于测试案例准备和验收的方法。短交付周期,无论是两周还是四周,都给整个团队带来了巨大的变化,开发和测试不再是独立而又顺序的过程,开发和测试互相穿插,成为一个快速反馈的过程。持续集成是软件系统开发过程的晴雨表,其中价值相当大的自动化测试仍然和我们的测试工作脱不了干系。

  可见,敏捷和它的方法,虽然没有显式地给测试工作以指导建议,但隐式地要求了我们测试人员仔细思考测试本身在敏捷项目中所需要发生的变化,我们测试人员的职责和工作范畴发生了哪些变化。

  与敏捷开发一样,敏捷测试针对不同的项目上下文和不同的团队组成和背景,有不同的适配模式。跟敏捷软件开发的宣言类似,敏捷测试也有一系列可以恪守的原则。经过不断实践和经验,ThoughtWorks的同事同样提出了《敏捷测试宣言》:

  1、Collaborative ownership over detached objectivity

  2、Targeted automation over widespread anti-regression

  3、Defect prevention over defect reporting

  4、Exploratory testing over predetermined scripting

  第一点与完整团队有关。虽然独立的测试团队可以从外部视角观察软件质量,但真正的软件质量来自测试人员属于一部分的完整团队,不再区分彼此的开发团队和测试团队,不再有彼此分离的目标。整个团队为软件质量和客户价值共同负责。

  第二点针对性自动化测试胜过广泛的回归测试。随着软件系统开发的进展,后期引入的新功能和缺陷都会带来大量和重复的回归测试,自动化测试是代替人工繁琐而无聊的回归测试的唯一办法。

  第三点提到的如何对待缺陷恐怕是时下各个测试团队最为纠结的内容了。预防缺陷胜过报告缺陷,预防缺陷才是测试工作最大的价值所在。敏捷测试会尽早介入软件系统的开发过程,和业务分析师、客户分析需求和价值所在,以用户故事和验收条件来驱动开发,以短周期迭代和持续集成为反馈,可以尽早发现存在的缺陷,从而极大降低后期才报告以及修复缺陷所带来的高额成本。在我的团队,测试人员甚至可以和开发人员结对,共同确认缺陷根源,修复缺陷,并添加自动化测试确保缺陷不会再次发生。

  第四点的探索性测试的重要性没有人会怀疑,测试人员可以凭借自己的经验积极、自由地发现质量问题,而不仅仅是反复运行已经定义好的测试。这样可以证明软件不仅仅做了它该做的事情,还证明软件没有做它不该做的事情。

posted @ 2012-07-23 10:00 顺其自然EVO 阅读(193) | 评论 (0)编辑 收藏

【SQL Server】万事无忧——备份和恢复

  在SQL Server中,使用数据库备份和还原工具可以创建数据库的拷贝,将该拷贝放到安全的地方,当服务器崩溃或数据被破坏时,该拷贝就可以用于还原数据库。这就是我们本篇文章要说的备份和恢复。

  (1)完整备份与恢复

  制作数据库中所有内容的副本,在备份过程中需要花费的时间和空间最多,不宜频繁进行

  恢复时,仅需要恢复最后一次全库备份即可

  备份:backup database 数据库名 to 备份设备名 with [name='备份的名称'][init /noinit]

<SPAN style="FONT-SIZE: 18px">backup database MagDB to MagDb_1 with init</SPAN>

  恢复:restore database 数据库名 from 备份设备名  with [norecovery/recovery]

<SPAN style="FONT-SIZE: 18px">restore database MagDb
from MagDb_1
with norecovery</SPAN>

  (2)差异(增量)备份与恢复

  只备份最后一次全库备份后被修改的数据,备份的时间和空间较少

  恢复时,先恢复最后一次完整备份,再恢复最后一次差异备份

  备份:backup database 数据库名 to 备份设备名 with differential  [name='备份的名称']

<SPAN style="FONT-SIZE: 18px">backup database MagDb to MagDb_1 defferential</SPAN>

  恢复:restore database 数据库名 from 备份设备名  with [norecovery/recovery]

<SPAN style="FONT-SIZE: 18px">restore database MagDb
from MagDb_1
with file =2,
recovery</SPAN>

  (3)事务日志备份与恢复

  只备份最后一次日志备份后所有的事务日志记录,备份时所用的时间和空间更少

  恢复时,可以指定恢复到某一事务;可以将其恢复到某个破坏性操作执行前的一个事务,这是全库备份和差异备份所不能做到的,但利用日志备份进行恢复时,需要重新执行日志记录中的修改命令,来恢复数据库中的数据,所以通常恢复的时间较长;先恢复最后一次全库备份,再恢复最后一次差异备份,再顺序恢复最后一次差异备份以后进行的所有事务日志备份

  备份:backup log 数据库名 to 备份设备名 with init/noinit

<SPAN style="FONT-SIZE: 18px">backup log DocDb to disk='c:\databak\DocDb_1.bat'</SPAN>

  恢复:restore log 数据库名 from 备份设备名 with [norecovery/recovery]

<SPAN style="FONT-SIZE: 18px">restore log DocDb
from disk='c:\databak\DocDb1.bat'</SPAN>

  (4)文件和文件组备份与恢复

  备份某个数据库文件或数据库文件组,必须与事务日志结合才有意义

  恢复时,使用事务日志,使所有的数据文件恢复到同一个时间点

  备份:backup database 数据库名  file='文件的逻辑名称'(filegroup) to 备份设备名 with init/noinit

<SPAN style="FONT-SIZE: 18px">backup database DocDb
file='DocDb_Data'
to disk='c:\databak\Docfile1.dat'</SPAN>

  恢复:restore database 数据库名  file='文件的逻辑名称'(filegroup) from 备份设备名

<SPAN style="FONT-SIZE: 18px">restore database DocDb
file="DocDb_Data"
from disk="c:\databak\Docfile1.dat"</SPAN>

  让您的数据万事无忧吧,做好备份,恢复,易如反掌。

posted @ 2012-07-23 09:39 顺其自然EVO 阅读(261) | 评论 (0)编辑 收藏

 《XPP极速编程实践》

 《XPP极速编程实践》主要介绍了XPP的模式,在此模式下PD,Dev,QA,DevOps各角色的职责与定位,以及如何持续快速交付高质量产品。

  XPP的模式--面向交付开发与传统的面向测试开发区别:

  极限编程的模式,面向交付的开发:有测试的工作,但没有真正的测试环节存在。开发写完代码,直接上线。没有经过严格的测试,会不会出现质量倒退呢,其实是赋予测试一些定的含义。

  开发在编码阶段加入:代码审查、单元测试、集成测试;在交付阶段:加入一个新的角色DevOps,从复杂的TC编写中释放出来,而是做用例审查、验收测试、自动化回归。

  需要建立持续集成的开发环境,便于开发自行测试。

  在Xpp模式下,人员的职责和定位:

  如何更快的交付

  1、需求管理方面:将需求拆分为小的端到端可测试的用户case,一个需求必须在一次发布中完成,实现小步快跑。

  2、在开发过程中进行代码审查,单元测试,代码覆盖率,集成测试——达标后提交发布单,去掉了传统的测试环节。测试驱动开发编写自动化测试用例,促使提高设计的可测性。

  3、持续的集成测试:单元测试 → 集成测试 → 系统级测试

  4、规范的交付流程

  5、充分利用各类工具和自动化平台。如淘宝现有的任务管理工具redmine、自动化发布平台、自动化测试平台TOAST、各类自动化测试工具(单元测试工:mocha,should;代码覆盖率工具:jscoverage;集成测试工具:helium)。

  如何更好的交付

  1、代码审查 & 持续集成。代码须由统一的负责人审核通过才能。分支开发,主干提交,对分支和主干建立持续集成环境,发布前自动化脚本去除测试代码。

  2、测试驱动开发。PD、Dev、DevOps一起制定测试清单,在开发环境中测试通过后提交发布;进行增量式的开发:迭代过程,测试—编码—重构,测试先行

  3、测试用例审查。以测试清单为评判标准,重点关注变更代码;保证主流程质量;定期做用例review,完善场景和用例;结合代码覆盖率报告进行单元测试代码审查;集成测试审查,前端的关注主流程,后端的关注接口和数据校验。

  4、验收测试。由产品经理执行并确定具体的用例,主要关注用户体检、样式、浏览器兼容性等方面的问题。

  5、建设发布通道

  6、对发布过程进行质量控制。前端应用优先发布、自动化七层校验失败立即回滚,发布过程开发关注应用层面监控、DevOps关注发布层面的监控。

  7、发布后的监控。系统级:CPU,Memory,Network IO,Disk IO等;应用级:线程,队列,对象,调用,日志等;业务级:产品级流程交互、数据展现等;用户级:用户行为关键指标变动等。 《XPP极速编程实践》主要介绍了XPP的模式,在此模式下PD,Dev,QA,DevOps各角色的职责与定位,以及如何持续快速交付高质量产品。

  XPP的模式--面向交付开发与传统的面向测试开发区别:

  极限编程的模式,面向交付的开发:有测试的工作,但没有真正的测试环节存在。开发写完代码,直接上线。没有经过严格的测试,会不会出现质量倒退呢,其实是赋予测试一些定的含义。

  开发在编码阶段加入:代码审查、单元测试、集成测试;在交付阶段:加入一个新的角色DevOps,从复杂的TC编写中释放出来,而是做用例审查、验收测试、自动化回归。

  需要建立持续集成的开发环境,便于开发自行测试。

  在Xpp模式下,人员的职责和定位:

  如何更快的交付

  1、需求管理方面:将需求拆分为小的端到端可测试的用户case,一个需求必须在一次发布中完成,实现小步快跑。

  2、在开发过程中进行代码审查,单元测试,代码覆盖率,集成测试——达标后提交发布单,去掉了传统的测试环节。测试驱动开发编写自动化测试用例,促使提高设计的可测性。

  3、持续的集成测试:单元测试 → 集成测试 → 系统级测试

  4、规范的交付流程

  5、充分利用各类工具和自动化平台。如淘宝现有的任务管理工具redmine、自动化发布平台、自动化测试平台TOAST、各类自动化测试工具(单元测试工:mocha,should;代码覆盖率工具:jscoverage;集成测试工具:helium)。

  如何更好的交付

  1、代码审查 & 持续集成。代码须由统一的负责人审核通过才能。分支开发,主干提交,对分支和主干建立持续集成环境,发布前自动化脚本去除测试代码。

  2、测试驱动开发。PD、Dev、DevOps一起制定测试清单,在开发环境中测试通过后提交发布;进行增量式的开发:迭代过程,测试—编码—重构,测试先行

  3、测试用例审查。以测试清单为评判标准,重点关注变更代码;保证主流程质量;定期做用例review,完善场景和用例;结合代码覆盖率报告进行单元测试代码审查;集成测试审查,前端的关注主流程,后端的关注接口和数据校验。

  4、验收测试。由产品经理执行并确定具体的用例,主要关注用户体检、样式、浏览器兼容性等方面的问题。

  5、建设发布通道

  6、对发布过程进行质量控制。前端应用优先发布、自动化七层校验失败立即回滚,发布过程开发关注应用层面监控、DevOps关注发布层面的监控。

  7、发布后的监控。系统级:CPU,Memory,Network IO,Disk IO等;应用级:线程,队列,对象,调用,日志等;业务级:产品级流程交互、数据展现等;用户级:用户行为关键指标变动等。

posted @ 2012-07-20 10:06 顺其自然EVO 阅读(206) | 评论 (0)编辑 收藏

持续交付与传统敏捷的矛盾

 我在采用持续交付的组织中和开发团队工作一起工作,发现很多开发者认为的正确的敏捷团队的工作方式,在这里跑得不是很顺畅。我认为传统敏捷与持续交付的矛盾的根本在于,二者是采用不同的方式把软件变得“可以发布“(ready to release)的。

  软件交付的演进

  使软件变得可以发布的过程一直在不停进化,下面是一个简要的介绍:

  瀑布模型

  瀑布模型认为,当一个软件所有的功能都发开完毕的时候(也就是功能完整的时候),才可以发布。

  敏捷:

  敏捷引入的思想是,在整个开发过程中,软件都应该“可以发布”。许多敏捷的版本(在这篇文章里被称为传统敏捷)都认为,“可以发布”应该在固定周期的间隔点上完成。

  持续交付:

  持续交付是敏捷的一个子集,在持续交付中团队会保持软件在开发过程的所有时间内都可以发布。它和传统敏捷不同之处在于,持续交付在开发过程中不会有停下来然后创建发布版本的过程。

  持续性交付不是指更短的周期

  从传统的敏捷开发流程变成可持续性交付,不是指把软件发布的周期变短。每天晚上做发布版本仍然不是可持续性交付。可持续性交付是说要把”做可以发布的软件”这个动作本身从开发过程中去掉,取而代之的是保持软件在开发的过程中始终是可以发布的。

  可以发布不是意味着真正的发布

  有一个普遍的误解是可持续性交付就是非常频繁地发布出产品。而当一些组织把每天数次发布软件当作是持续交付的标杆时,就更加深了这一误解。可持续性交付不是一定要频繁的发布,它只是要求在开发过程中的任何一个点上,用非常少的工作,软件就能够发布(可参考Jez Humble的文章,可持续性交付VS可持续性部署)。尽管具备这一能力为更加频繁的发布敞开了大门,但是许多团队还是从持续交付的实践中,找到了压倒性的证据,来证明即便发布不是很频繁时,持续交付也是有用的。

  持续交付和传统敏捷的冲突点

  我前面讲过,有时候持续交付和开发团队所认为是“正确”的敏捷实践流程有一些矛盾。

  冲突点:当有工作没有完成时,软件依然是可发布的

  其中一个冲突点是,一个迭代结束时,代码库中是否可以包含未完成的用户故事(user stories)或者bug修复。我在上一篇关于迭代的帖子中做了探讨。这个问题主要是源于,传统敏捷认为在迭代结束时,team停止开发,并且来做准备软件发布的一些额外工作,但是,如果团队采用持续交付,让软件可发布就没什么额外的工作需要做。

  更有甚者,持续交付团队甚至认为,通过使用功能切换等技术,他们的代码即使在还有功能没有完成也可以发布成产品。这也从另外一个方面说明,团队在迭代结束时能够达到可以发布的要求,即使有未完成的用户故事。

  这可能稍微有点难理解,团队肯定还是可以要求在迭代结束点上所有的工作都必须完成,但是这容易让人感觉是团队原有的正常开发的节奏被随便打断了。持续交付不是要求没有时间盒的迭代,这两种实践其实是互补的。

  冲突点:snapshot(软件快照)/发布版本(release build)

  许多开发团队把软件的版本分为“snapshot”版本和“release”版本。这个并不是敏捷所特有的,而是随着Maven的兴起,被深深植入了Java开发中,因为Maven把snapshot的概念放入了它的设计核心中。这种方案把开发周期划分成两个阶段,在软件开发过程中使用snapshot,当软件成为可以发布状态时才创建release版本。

  很明显,这种发布周期的划分和持续交付的“软件应该总是可以发布”的理念是相冲突的。持续交付通常采用的方式是只在开始创建一次版本,然后通过不同阶段的测试验证等一系列串行工作来对版本进行改进,如果使用Maven,要用两种方式创建版本,这种方式就不行了。

  其实完全可以使用Maven做持续交付,比如说,为每个版本创建一个release build。当然,这个会和Maven的“release build只以生产部署为目的,不会经常创建”的理念矛盾。而且,像Nexus和Artefactory这样的私服都有删除旧的snapshot版本的清理功能,但不允许删除release版本。所以一个活跃的持续交付团队,一天可以产生几十个版本,这样很容易就吃掉服务器上几G到几T的空间。

  矛盾点:更着重测试可部署性

  标准的持续交付的实践方式是,通过基本的持续集成自动地把每个版本部署到与真实生产环境尽量贴近的模拟环境中,使用相同的发布流程和工具。这对验证每次提交的代码是否是“可以发布”是至关重要的,但是这样对持续集成的要求比现在大部分开发团队正在使用的要高很多。

  举个例子,在没有要求持续发布的持续集成,可能会使用Ant或者Maven将应用发布到嵌入应用服务器然后进行自动的功能测试。开发者使用和维护都很方便,但是这很可能不是生产环境中应用发布的方式。

  所以持续交付团队会自动化发布到一个更贴近真实生产的环境,包括不同的网页/app/数据层,并且使用在真正生产中使用的部署工具。当然,这种更像生产的部署阶段更加可能出错,因为它增加了复杂性,而且可能对开发者而言更难以维护和修正,因为这些工具更像是给系统管理员而不是给开发者使用的。

  不过这是个机会,可以和管理运营团队一起创建一个更可靠、更易于支持的部署流程。但是实现和稳定这一流程的难度会比较大,可能会影响开发的进度。

  值得采用持续交付吗?

  考虑到有这么多冲突的地方,那持续交付有什么好处,值得我们从传统敏捷迁移过来呢?特别是对于那些实际上不太可能在一次迭代中有好几次发布到生产环境的团队来说,更是要问这个问题。值得这么做的原因如下:

  尽早发现部署可能遇到的问题以降低风险

  增加灵活性,组织可以选择在任何时候发布,并把附加的代价和风险控制到最小

  把生产发布涉及的每个人拉进来(比如QA、运营等),使得整个流程更有效率。组织必须识别出流程中的困难区域,并且通过自动化、更好的协作或者改进工作方法等方式找到克服它们的方法。

  通过持续的演练发布流程,组织会对这个过程很精通,然后发布就会变得自动化,就像阵痛过后自由的呼吸,像生孩子一样。

  提升软件质量,因为团队不能再像以前一样把问题留到后面,他们必须现在就解决。

  消除冲突

  当引入持续交付的时候,我以上所说的冲突点就会频繁出现。我希望当这些问题出现的时候,了解冲突的根本原因,可以有助于更好地讨论并解决它们。如果开发者一开始不愿意打破他们习惯的“正确”做事方式,或者认为持续交付所带来的串行工作太复杂,或者很难理解这些实践的目的和价值,那么我希望他们可以尽量开放地给自己一个机会去尝试一下。一旦这些实践方式根植于一个组织并且变得成熟,团队成员们往往会觉得很难退回到以前的做事方式。

  编者按:我重新定义了“传统敏捷”中让软件可以发布的方式。这个定义不是适用于所有敏捷实践,但是就我看到的,大部分主流概念都认为敏捷需要停下工作来将软件变得可发布。



posted @ 2012-07-20 10:04 顺其自然EVO 阅读(243) | 评论 (0)编辑 收藏

SQL Server 让你的数据来去自如——批处理

 比如说,我们现在需要建立一个数据库(create database),再建立一个表(create table),如果表的字段很少,手动添加就可以,一个一个插入到表中。

  那么如果字段很多怎么办呢?一个一个地插入恐怕是不行了,即使手不累,用不了一会,脑袋也晕了~

  那到底怎么办呢?别着急,批处理要大显身手了~~~

  什么是批处理?

  批处理:指包含一条或多条T-SQL语句的语句组,这组语句从应用程序一次性地发送到SQL Server服务器执行。SQL Server服务器将批处理语句编译成一个可执行单元(即执行计划),执行计划中的语名每次执行一次。

  批处理是如何存在的?

  脚本:批处理的存在方式,将一个或多个批处理文件组织到一起就是一个脚本,将脚本保存到磁盘文件上就是脚本文件。

  例如,把查询语句都写在一个文本文件里,然后双击一个bat文件,就自动执行文本文件里的语句。

  首先,新增一个批处理文件,linlin.bat

  其次,新增一个SQL脚本文件,linlin.sql

  在linlin.bat中输入:

<SPAN style="FONT-SIZE: 18px">osql  -U  sa  -P  123456 -i c:\linlin.sql </SPAN>

  同样在bat文件中,输入上面一行,在linlin.sql输入脚本

  如:

<SPAN style="FONT-SIZE: 18px">use 数据库名
go
select * from 表名
go</SPAN>

  以上的小例子就是通过批处理来执行SQL语句,下面我们来说一下,建立批处理时的一些注意事项:

  1、创建默认值CreateDefault、创建规则Create Rule、创建触发器Create Trigger、创建视图 Create view等语句在同一个批处理中只能提交一个

  2、删除的对象,在同一批处理中不能再次引用

  3、不能把规则和默认值绑定到表字段或者自定义字段上之后,立即在同一个批处理中使用它们

  4、不能定义一个check约束之后,立即在同一个批处理中使用

  5、不能修改表中一个字段名之后,立即引用新字段

  6、使用Set语句设置的某些set选项不能应用于同一个批处理中的查询

  7、若批处理中的第一个语句是执行某个存储过程的execute语句,则execute关键字可以省略

  相信学会了批处理,在工作中我们会更加得得心应手,让数据来去自如。

posted @ 2012-07-20 09:53 顺其自然EVO 阅读(251) | 评论 (0)编辑 收藏

理解SQL SERVER中的逻辑读,预读和物理读

  SQL SERVER数据存储的形式

  在谈到几种不同的读取方式之前,首先要理解SQL SERVER数据存储的方式。SQL SERVER存储的最小单位为页(Page)。每一页大小为8k,SQL SERVER对于页的读取是原子性,要么读完一页,要么完全不读,不会有中间状态。而页之间的数据组织结构为B树。所以SQL SERVER对于逻辑读,预读,和物理读的单位是页。

  SQL SERVER一页的总大小为:8K

  但是这一页存储的数据会是:8K=8192字节-96字节(页头)-36字节(行偏移)=8060字节

  所以每一页用于存储的实际大小为8060字节。

  比如上面AdventureWorks中的Person。Address表,通过SSMS看到这个表的数据空间为:

  我们可以通过公式大概推算出占用了多少页:2.250*1024*1024/8060(每页的数据容量)≈293 - 表中非数据占用的空间≈290(上图中的逻辑读取数)

  SQL SERVER查询语句执行的顺序

  SQL SERVER查询执行的步骤如果从微观来看,那将会非常多。这里为了讲述逻辑读等概念,我从比较高的抽象层次来看:

  图有些粗糙。

  下面我解释一下图。当遇到一个查询语句时,SQL SERVER会走第一步,分别为生成执行计划(占用CPU和内存资源),同步的用估计的数据去磁盘中取得需要取的数据(占用IO资源,这就是预读),注意,两个第一步是并行的,SQL SERVER通过这种方式来提高查询性能。

  然后查询计划生成好了以后去缓存读取数据。当发现缓存缺少所需要的数据后让缓存再次去读硬盘(物理读)

 最后从缓存中取出所有数据(逻辑读)。

  下面我再通过一个简单的例子说明一下:

  这个估计的页数数据可以通过这个DMV看到:

  当我们第一次查询完成后,再次进行查询时,所有请求的数据这时已经在缓存中,SQL SERVER这时只要对缓存进行读取就行了,也就是只用进行逻辑读:


posted @ 2012-07-20 09:47 顺其自然EVO 阅读(209) | 评论 (0)编辑 收藏

使用Java管理千台规模Linux服务器_入门

前东家是一家游戏公司,老板很好,当时工作也留下了很多自己原创的管理脚本。现在分享一下在办公环境使用Java、Jsch登录VPN管理Linux的脚本(此处实现JAVA调用Linux上备份Mysql的shell作为示例),希望对运维的朋友有帮助,尽快从繁杂的服务器管理工作中脱离出来。

  主要的实现思路:

  如果需要先登录VPN才能连接游戏服务器,需要将游戏服务器的ssh端口(一般是22)映射到本地办公电脑的端口上(如5555),然后ssh连接本地办公电脑的5555端口,这样就可以连接到游戏服务器,并可以管理游戏服务器了。

  当您学会通过VPN连接Linux服务器后,如果只在内网环境,不使用VPN,就更简单了,此外不再详述。Jsch的example里也有介绍。

  代码:使用Jsch透过VPN

  1. package com.daily.wednesday;  
  2. import java.io.IOException;  
  3. import java.io.InputStream;  
  4. import java.sql.Connection;  
  5. import java.sql.DriverManager;  
  6. import java.sql.ResultSet;  
  7. import java.sql.SQLException;  
  8. import java.sql.Statement;  
  9. import com.daily.util.DataBaseConnection;  
  10. import com.jcraft.jsch.Channel;  
  11. import com.jcraft.jsch.ChannelExec;  
  12. import com.jcraft.jsch.JSch;  
  13. import com.jcraft.jsch.JSchException;  
  14. import com.jcraft.jsch.Session;  
  15. public class BackUpMysql3 {  
  16.     public static void main(String args[]) {  
  17.         // 读取数据库配置 
  18.         DataBaseConnection dataBaseConnection = new DataBaseConnection();  
  19.         String dataBaseConfigForWrite[] = new String[3];  
  20.         dataBaseConfigForWrite = dataBaseConnection.loadDataConfig();  
  21.         Connection conn = null;// 数据库连接 
  22.         Statement stmt = null;// 数据库表达式 
  23.         ResultSet rs = null// 结果集 
  24.         int rowcount = 0;// 总记录数 
  25.         String sql = "select * from servers_maint_wednesday";  
  26.         try {  
  27.             conn = DriverManager.getConnection(dataBaseConfigForWrite[0],  
  28.                     dataBaseConfigForWrite[1], dataBaseConfigForWrite[2]);  
  29.             stmt = conn.createStatement();  
  30.             rs = stmt.executeQuery(sql);  
  31.             rs.last();  
  32.             rowcount = rs.getRow();// 总记录数 
  33.             rs = stmt.executeQuery(sql);  
  34.         } catch (SQLException e) {  
  35.             e.printStackTrace();  
  36.         }  
  37.         // 定义游戏服务器IP的数组,游戏服务器IP存在数据库中。 
  38.         String privateIpaddress[] = new String[rowcount];  
  39.         String remark[] = new String[rowcount];// 定义游戏区名称 
  40.         String programPath[] = new String[rowcount];// 定义程序路径 
  41.         String backMysqlShellPath[] = new String[rowcount];// 定义mysql备份脚本路径 
  42.         int j = 0;  
  43.         try {  
  44.             while (rs.next()) {  
  45.                 privateIpaddress[j] = rs.getString("privateipaddress");  
  46.                 remark[j] = rs.getString("remarks");  
  47.                 programPath[j] = rs.getString("programpath");  
  48.                 backMysqlShellPath[j] = rs.getString("backmysqlshellpath");  
  49.                 j++;  
  50.             }  
  51.         } catch (Exception e) {  
  52.             e.printStackTrace();  
  53.         } finally {  
  54.             try {  
  55.                 if (rs != null) {  
  56.                     rs.close();  
  57.                 }  
  58.                 if (stmt != null) {  
  59.                     stmt.close();  
  60.                 }  
  61.                 if (conn != null) {  
  62.                     conn.close();  
  63.                 }  
  64.             } catch (Exception e) {  
  65.                 e.printStackTrace();  
  66.             }  
  67.         }  
  68.         // 调用mysql备份方法 
  69.         for (int n = 0; n < privateIpaddress.length; n++) {  
  70.             try {  
  71.                 try {  
  72.                     backUpMysql(privateIpaddress[n], backMysqlShellPath[n],remark[n]);  
  73.                 } catch (IOException e) {  
  74.                     // TODO Auto-generated catch block 
  75.                     e.printStackTrace();  
  76.                 }  
  77.             } catch (JSchException e) {  
  78.                 // TODO Auto-generated catch block 
  79.                 e.printStackTrace();  
  80.             }  
  81.         }  
  82.     }  
  83.     /** 
  84.      * 备份mysql数据库的方法 
  85.      * @param privateip 
  86.      * @param backMysqlShellPath 
  87.      * @throws JSchException 
  88.      * @throws IOException 
  89.      */ 
  90.     public static void backUpMysql(String privateip, String backMysqlShellPath, String remark)  
  91.             throws JSchException, IOException {  
  92.         // 登录到服务器 
  93.         int rport;  
  94.         JSch jsch = new JSch();  
  95.         String host = "dl.dengdie.com"//此处为VPN服务器地址 
  96.         String user = "admin"//VPN用户名 
  97.         Session sessionForBack = jsch.getSession(user, host, 22);  
  98.         rport = 22;  
  99.         sessionForBack.setPassword("&*&&&&lalaflls"); //VPN密码 
  100.         java.util.Properties config = new java.util.Properties();  
  101.         config.put("StrictHostKeyChecking""no");  
  102.         sessionForBack.setConfig(config);  
  103.         sessionForBack.connect();//登录到VPN服务器 
  104.           
  105.         // 建立与游戏服务器的ssh转发连接:即将游戏服务器的22号ssh端口映射的本地办公电脑的53238端口。       
  106.         sessionForBack.setPortForwardingL(53238, privateip, rport);  
  107.         try {  
  108.             JSch jschToBack = new JSch();  
  109.             Session sessionToBack = jschToBack.getSession(user, "127.0.0.1",  
  110.                     53238); //连接本地办公电脑的53238端口,就相当于连接了游戏服务器的22号端口。 
  111.             sessionToBack.setPassword("&*&&&&lalaflls");  
  112.             sessionToBack.setConfig(config);  
  113.             sessionToBack.connect();  
  114.             //backMysqlShellPath实际上是游戏服务器上备份Mysql数据库的一个脚本,此脚本请您自行实现,网上很多实例。 
  115.             String command = backMysqlShellPath;  
  116.             //打开执行命令的隧道,并执行命令。 
  117.             Channel channel = sessionToBack.openChannel("exec");  
  118.             ((ChannelExec) channel).setCommand(command);  
  119.             channel.setInputStream(null);  
  120.             ((ChannelExec) channel).setErrStream(System.err);  
  121.             InputStream in = channel.getInputStream();  
  122.             channel.connect();  
  123.             byte[] tmp = new byte[1024];  
  124.             while (true) {  
  125.                 while (in.available() > 0) {  
  126.                     int i = in.read(tmp, 01024);  
  127.                     if (i < 0)  
  128.                         break;  
  129.                     System.out.print(new String(tmp, 0, i));  
  130.                 }  
  131.                 if (channel.isClosed()) {  
  132.                     System.out.println(remark + "Mysql备份完毕!");  
  133.                     System.out.println("exit-status: " 
  134.                             + channel.getExitStatus());  
  135.                     break;  
  136.                 }  
  137.                 try {  
  138.                     Thread.sleep(1000);  
  139.                 } catch (Exception ee) {  
  140.                 }  
  141.             }  
  142.             channel.disconnect();  
  143.             sessionToBack.disconnect();  
  144.             sessionForBack.disconnect();  
  145.         } catch (Exception e) {  
  146.             System.out.println(e);  
  147.         }  
  148.     }  
  149. }

posted @ 2012-07-20 09:39 顺其自然EVO 阅读(247) | 评论 (0)编辑 收藏

PDCA理念融入软件测试

  摘要:软件测试作为软件质量保障的重要手段,PDCA循环是全面质量管理所应遵循的科学程序。本文结合软件测试工作的特点,通过文档规范的方式,将PDCA的理念融入软件测试,提出一套软件测试工作的流程。

  关键字:软件测试、PDCA、测试流程

  1、引言

  PDCA循环又叫戴明环,是美国质量管理专家戴明博士提出的,它是全面质量管理所应遵循的科学程序。全面质量管理活动的全部过程,就是质量计划的制订和组织实现的过程,这个过程就是按照PDCA循环,不停顿地周而复始地运转的。PDCA 描述如下,PLAN:活动、控制、资源、目标;DO:按计划实施;CHECK:监控和测量一致性和有效性;ACTION:分析/回顾/改进/提高有效性。软件测试是有计划、有组织和有系统的软件质量保证活动,是软件工程的重要组成部分。本文结合PDCA循环对于质量改进的作用,依靠文档管理,将PDCA 理念融入软件测试。在软件测试流程中,结合PDCA 理念,各个阶段进行如此诠释,PLAN:编写测试计划;DO:按计划开展测试工作;DO:按计划开展测试工作;ACTION:维护测试文档。

  2、PLAN:编写测试计划

  软件测试组接到测试项目后,测试工程师首先编写《系统测试计划》,为本次测试工作做好安排。

  根据研发部门提交的《项目总体需求说明书》《项目模块需求说明书》《项目概要设计说明书》《项目详细设计说明书》及《数据库设计说明书》等内容,测试工程师编写《系统测试计划》。测试计划中包含编写目的、参考资料、测试内容、测试环境、测试方案、测试通过标准、风险评估、测试组织和时间安排等内容,包括了PLAN中应该进行活动、控制、资源、目标等全部内容,实现了做测试工作的计划性。

  3、DO:按计划开展测试工作

  完成测试计划后,即按照计划的时间要求进行测试工作。

  测试工程师依据《总体需求说明书》、《模块需求说明书》、《概要设计说明书》和《验收测试计划》分析测试需求,撰写该项目的《测试需求说明书》。软件测试的核心文件《系统测试需求说明书》是列出项目所有的测试点,保证了软件测试的有据可依。测试工程师根据《测试需求说明书》编写《测试用例》。

  测试负责人依据《系统测试计划》及项目进度向测试工程师分配测试任务;测试工程师向测试负责人领取测试资料,执行测试。本轮测试结束后,测试工程师编写《系统测试报告》。

图1 测试设计工作流程

字体:        | 上一篇 下一篇 | 打印  | 我要投稿 

  4、CHECK:审核和评审测试文档

  审核和评审是PDCA方法中最重要的组成部分,在软件测试中主要是依靠对测试文档的审核和评审,来保证测试工作的质量。

  《系统测试计划》是测试工作的纲领性文件,是对整个系统测试的工作安排。测试工程师完成后,需要由测试负责人进行审核,审核通过后由研发和测试人员组成的评审小组进行评审,保证了测试计划的合理性。

  《测试需求说明书》是整个测试工作的核心文件,列出项目的所有测试点。首先由测试负责人进行审核,审核通过后组织评审,项目经理和评审小组参与进行评审,要求有测试记录。从研发和测试的角度保证了尽可能不遗漏测试点,也能有效减少测试组与研发部门的分歧。

  《系统测试用例》是根据《测试需求说明书》的测试点扩展而来,测试工程师完成后,由测试负责人审核《系统测试用例》,并提出修改意见。

  《系统测试报告》是每轮测试结束后,测试工程师编写《系统测试报告》,然后测试负责人审核《系统测试总结报告》。审核通过后,将《系统测试报告》交给测试负责人、项目经理、评审小组成员进行审批;审批不通过,则测试人员进行修改;审批通过,更新系统测试用例后,一轮测试结束。

图2 系统测试工作流程

  5、ACTION:维护测试文档

  文档《系统测试计划》和《测试需求说明书》都需要经过测试负责人的审核和评审小组的评审,《系统测试用例》要由测试负责人进行审核,《系统测试总结报告》由测试负责人审核外,还要进行项目经理、评审小组成员进行审批和会签,在此过程中,会有很多测试工程师要按照评审意见进行修改,达到了分析改进提高的效果,保证测试工作的质量。

  6、总结:提高测试工作效率

  将PDCA方法融入软件测试工作流程中,使得测试流程更加规范,提高了测试工作效率。编写测试计划,使得测试工作按部就班;规范的工作内容,在各个阶段都明确的产出物,方便领导对测试工作的检查;增加测试文档的评审机制,既降低测试组与研发部门沟通成本,减少分歧,又提高了软件测试的质量。

版权声明:51Testing软件测试网原创出品,转载时请务必以超链接形式标明文章原始出处、作者信息和本声明,否则将追究法律责任。

http://www.51testing.com



posted @ 2012-07-19 10:19 顺其自然EVO 阅读(542) | 评论 (2)编辑 收藏

软件测试入门

完成测试任务

  在大多测试职位中,通常都会提交Bug。Bug质量和描述都很重要,建议:

  ● Bug简述应一目了然,不能含糊,长度不得超过30个字。

  ● 提交的Bug应用客观的书面语,避免使用口语。

  ● 测试中一旦发现BUG,需要及时提交BUG。

  ● 在提交Bug前,应查询库里已有的Bug,防止同样的Bug重复提交 。

  ● 优先级别、严重性级别、重复性定义尽可能准确。

  ● Bug描述中千万不要有错别字,在细节处也都要随时体现质量人员的素质。

  总之,按时、高质量地完成安排的任务,这是最重要的。在这一过程中,如遇上问题,需要及时想办法解决;若自己无法独立解决,应及时请教别人。总之,一定要准时、高质量完成任务,如无法完成,一定要提前报告给你的上级。

  你做到了吗?

  进入公司后,能够快速熟悉公司文化、开发及项目流程,并融入其中。转正前能够达到:

  ● 熟悉基本测试理论,熟悉业务标准,能很好地运用测试理论知识,独立编写测试用例设计。

  ● 熟练运用必要的测试工具。

  ● 独立、按时完成测试任务。

  总结

  亲爱的朋友,不知道这些内容对你是否有帮助?我只想告诉你们,不管遇上何种困难,只要有信心,努力后一定是可以解决的。我的一位老师曾经在我困难的时候说,可能这个世界从来都不是公平的,有的人生下来就拥有很多,而有的人注定要非常努力后才能获取那么一点点,但是永远别失去信心,相信自己努力后,明天一定比今天好!感谢曾经给我指导、帮助的朋友!  编者之话

  亲爱的朋友,本文主要是针对打算进入软件测试领域的朋友们编写的。在我的面试经历中,我经常会遇见很多刚走出大学校门的朋友。他们都非常优秀,但是由于各种原因,例如因经济原因无法参与专业培训、短期无法找不到工作而准备放弃在大城市奋斗等,在职业选择方面非常迷茫。我非常希望能将自己的经验跟大家分享,如能对年青朋友们有一些帮助,我就非常高兴。感谢你们阅读本文,谢谢!

  职业发展

  “你为什么选择软件测试?”。面试时很多人回答:“因为软件测试简单”。这样的回答其实很糟糕。如果你是真心喜欢、热爱这个行业,再加上你的认真、踏实、负责、以及良好的团队合作等,恭喜你,不管你的计算机基础如何,你都能在软件测试行业有很好的发展前途!

  入门

  当你决定进入软件测试行业,若你对软件测试还不太了解,我建议你去书店选择软件测试相关书籍学习几天(特别提醒:对于重点知识、疑问等需做好笔记,并及时查阅资料将疑问解决掉)。经过这一阶段的学习,你可以知道哪些书写得比较好,可以从中买下1-2本书带回家仔细研究!

  面试

  恭喜你获得面试机会。这时候,你应该真诚、勇敢地参加面试。面试的时候,眼光请一定要正视考官,把你自信、优秀的一面充分展现出来。

  入职

  恭喜你进入软件测试行业。通常,通过一个月左右的时间熟悉、学习业务知识,如果你能顺利地把测试理论知识很好地应用于实际工作中,并按时完成上级安排的测试任务,到第二、三个月时你就基本具备独立执行测试任务的能力了。我相信,你一定能顺利转正。

  测试用例设计

  理论与实践相互结合是非常重要的。不知道其他公司对测试用例设计如何看待,而我始终是特别重视的。

  对于踏入这个行业的新人,我通常会花一周左右的时间对他们进行测试用例设计方面的培训,重点指导新人们如何将理论用于实践。

  测试用例模板

  我相信每家公司都有自己的测试用例设计模板。我采用的测试用例设计模板主要包含:

  ● 最小功能测试集:用于简单、快速地验证系统是否满足基本的功能需求(最小功能集最好能够做到全部自动化);

  ● 复杂功能测试集:用于进一步验证系统能否在复杂、或不常见的合法输入和操作下正常运行;

  ● 健壮性测试集:用于测试系统能否在各种异常输入、异常操作或者异常环境下正常响应,以及检测在出错之后系统能否正常运行,是否造成数据丢失、是否毁坏其它相关的软件和硬件等;

  ● UI测试集:编写跟UI设计相关的测试集。

  说明:

  最小测试集、复杂测试集、以及健壮性测试集都是根据需求、使用测试用例设计方法编写的。UI是根据产品UI设计文档编写的。

  在编写测试用例的时候,需要思考以下几个问题:

  ● 为什么功能性测试用例必须覆盖全部需求?

  这问题不回答了,大家一定理解。

  ● 哪种测试用例便于他人审核是否有效?哪种测试用例便于增加、删除、修改?

  具有树型结构、清晰层次关系的测试用例。审核人员一般会先审核树枝是否全面覆盖需求、是否有冗余,然后再审核树叶是否全面、是否有冗余。如果具有这样的层次关系,用户也能很好地维护测试用例。

  ● 哪种测试用例便于多项目共用?为什么要将功能与UI测试测试集分开?

  在测试用例设计中,将功能与UI测试用例分开,这样对于功能相同的需求,功能性测试用例就可以在多个项目中通用。为了功能性测试用例能够在多项目中通用,功能性测试用例需 要使用通用词语描述。UI用例应该只描述各产品UI的一些约束部分,参考后面电话模块测试用:当电话拨号盘没输入号码,键盘“灰显”等,这约束跟具体项目有关,属于UI用例。

  需求模块划分

  在设计测试用例前,充分理解需求是非常必要的。在此基础之上再对需求进行模块划分,形成一棵需求树(说明:划分模块的时候,需求可以重复。但重复不宜太多,否则需要思考划分的模块是否合理?)。

  电话模块需求树例子:

(未完,见下页续表)


(续表)

  根据需求编写测试用例

  基于需求的模块划分结果,结合边界值、等价类等测试用例设计方法,根据测试用例设计模板,编写功能性测试用例,即编写基本功能、复杂功能、健壮性测试用例。

  注意事项:

  1、理解测试用例设计方法特别重要。常用的测试用例设计方法有等价类、边界值等,建议大家能深入理解,针对不同类型的需求就可以选择一种或多种适宜的测试用例设计方法编写测试用例。

  2、建议每个测试目的下的测试用例不超过10条。如超过10条,需要再提出一层。这样做的目的,是便于自己和他人审核,因为单个目的下的测试用例如果太多,容易导致审核人员的思路混乱,从而很难对测试用例提出有效的改进意见!

  电话模块测试树例子:

posted @ 2012-07-19 10:00 顺其自然EVO 阅读(232) | 评论 (0)编辑 收藏

如何写一份良好的缺陷(Bug)报告

 没错,任何软件都存在bug,哪怕是我们自己也存在缺陷,因为程序员也是普通人,人是会犯错误的。当有人在使用软件时遇到bug,你需要使用邮件形成一份缺陷bug,发送给开发人员。开发者可以依据该报告定位问题,复现问题,修复问题。

  但是很多时候,开发人员很难理解提交上的缺陷报告,因为发送人并不了解我们需要的是什么,那如何与开发人员沟通以及如何写出一份缺陷报告,在这篇文章,我将教你如何写出一份清晰的缺陷报告能使开发者理解、复现、修复问题,这里下载缺陷报告模板。

  为什么要发送缺陷报告

  缺陷报告可以用很多方式来帮助我们的开发者。

  ● 他们能告知我们没有意识到的问题

  ● 他们能发现我们可能还没想到的新特性

  ● 他们能帮助我们感受到客户是如何使用我们的软件,以至于我们可以做的更好

  没有这些缺陷报告,我们就不知道出错的地方,我们需要它就像你唱歌跳舞时需要有软件的支持一样。

  什么时候发送缺陷报告

  ● 简单来说就是越快越好,详细来说就是:

  ● 当你看到一个错误消息时就发送错误报告

  ● 当屏幕是空白或者数据缺失就发送报告

  ● 当程序没有出现预期的结果时发送报告

  ● 当程序崩溃、死机、没有响应或者响应很慢时发送报告

  ● 当程序返回错误结果时发送报告

  ● 当你得不到想需要的结果时发送报告

  ● 如果你不清楚怎样做时发送报告

  ● 如果你不喜欢软件做的方式,或者软件老打搅你时,发送错报告

  ● 如果你想在系统中实现一个变通方案时发送报告

  缺陷报告需要有哪些内容

  缺陷报告应该包含很多信息,你提供的信息越多效果越好,对于开发者,就像我,提供一个纯文本文件模板给你填充然后邮件发给我,当然也有表格形式的,但是最期待你自己杜撰一份然后发给我。下面是一些必须包括的部分以及如何写好每部分:

   标题:创建一个简短的标题,让问题看起来更清晰。“应用崩溃”是一个很恼人的标题因为它没有足够的信息包括在这份报告里面。取而代之的是标题应该包含错 误消息和消息码,或者是结果的名称以及失败时你正在做的事情。例如:Error 402:访问拒绝当点击“发送邮件”这个例子就提供了缺陷系统的上下文信息。

  差:“程序崩溃”,“报错”,“Bug”

  好:“从’Kifu’中打印时5C79错误”,“’Kifu honors’报表为空”

  产品:用名称标识产品,告知你使用的是哪个版本。绝大部分软件都包含有版本信息。web应用的版本信息通常在页脚。

  差:“你的应用”

  好:”Kifu v1.01″

平台:告诉我们软件运行在什么平台。尤其是操作系统的名字及版本和游览器名称版本。特别是web应用,这些信息对我们很重要。

  差:“Windows”

  好:“Windows7,IE9”

  是否能重现:有些恼火的Bug是间歇性的出现,我们想预先知道,如果我们正在处理一个灵异事件或者正逢Bug出现时。

  差:留空白

  好:“每次”,“偶然”,“不重现”

  描述:这部分是很多人拿不定的地方,不知道怎么描述问题,在描述中做到包括下面的内容:

  ● 总结:用简洁的语言概括出Bug出现时你正在做的事情。从上下文开始,在操作应用的哪个部分。聚焦在你做的时候软件做了什么?

  差:“系统不能用了”

  好:在“honor report”页面单击“打印按钮”,但是报表是空的。

  ● 发生了什么:一步一步描述你做的事情当bug出现时,为什么你认为是错误的。事无巨细,打印出菜单的名称,页面标题,点击时的按钮或者链接的名称。做相同的操作是不是出现一样的错误。

  差:“空白报表”

  好:“点击 ‘File/Save as…’,’Save‘对话空弹出,然后点击‘OK’按钮,但是文件没有保存”

  ● 错误时什么:如果错误消息出现时,拷贝粘贴整个信息,这样更有利于我们跟踪错误。

  差:“有个错误,点击它始终读不出”

  好:“Error 403:访问拒绝”

  ● 复现的步骤:如果你可以让bug重现,那太好了,这能提供很大的帮助。一步步描述如何重现次bug。

  差:“打印没法使用”

  好:“从‘Honors Report’页面,点击‘打印按钮’”

  ● 预期结果:描述你预期发生的结果当bug发生时,这部分特别有用如果程序没有按照你期待的结果发生时,因为它很诡异。

  差:“我期待能正常工作”

  好:“我期待能看到‘Honors Reports’的PDF文件”

  真实结果:当bug发生时是怎么发生的,什么错误,为什么有错,或者如果错误抛出,抛出什么错。

  差:“没法用”

  好:“我收到是空的PDF文件,或者’403错误,访问拒绝’”

  ● 附件:如果你知道怎么截屏,做吧,附上一个简短的错误,截屏可以是错误之前或者发生错误之后,我们的开发者能够看到究竟发生了什么。如果应用有崩溃的日志,同样附上它。

  ● 联系方式:附上你的名字和email,我们可以让你提交的报告及时的得到答复,在我们不理解问题的描述时还能够询问你,如果你忘记附联系方式了,我们也就没法联系到你,也没法修复bug。

posted @ 2012-07-18 09:55 顺其自然EVO 阅读(451) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 305 306 307 308 309 310 311 312 313 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜