Hi, 如果有任何想法与我沟通, 请用: lifr_nj 在 msn.com

发布新日志

  • The relationship between QA and Dev

    2008-12-25 20:00:45

    An argue is raised between a QA engineer and a Dev engineer about whether supportdump should be provided for any single bug.

    I think this is one of the perfect examples reflecting the relationship between QA and Dev. Each side has its own interests, while meanwhile each side has to think of interests of the other so that both side can have a better life.


    Following is my reply mail.

    ================================================================

    Basically, I think both of you are kind of 牛角尖

    Theoretically, as Joe (Dev big boss) mentioned, All bugs must have a supportdump, but chances are it could be unnecessary and ineffective for QA when a supportdump will not benefit fixing a bug, in that case time is wasted in capturing and uploading supportdump.

    So my opinion for QA to handle with this issue is be practical and flexible”,

    If you are very sure that supportdump isnt needed, for example a GUI layout problem, just file a bug without supportdump.

    If its a server side bug or, you are not so sure, file a bug with supportdump, remember supportdump will never do harm.

    If you have made a wrong judgment and Dev comes to you asking for supportdump, just make one then upload it, no argue as Dev, not QA, is responsible for and capable of fixing the bug.

    I personally don't  like there is a rule or something everyone has to obey, I believe in for over 95% cases QA and Dev can come to a same judgment regarding if a supportdump is needed. I think this is so-called harmonious in our team :)

  • 中秋千岛湖骑行流水账

    2008-09-20 19:41:21

    中秋千岛湖骑行流水账

     

    时间: 9/13-9/15(3)

    总里程:270

    总骑行时间:15小时42分钟

    平均时速:18.23

    最高速度:51.7

     

    9/13 礼拜六 晴下午阵雨

    早上6点起床,骑车到上海南站21公里,1个小时3分钟。和andy会和后,进站遇到了一个小麻烦,一个穿白衣的中年人装13,非得不让我们进去。好说歹说根本没用。只好先出去,等他走了再进去。还好其他工作人员对我们都是一路放行,我和andy一路狂奔上了车,刚上车列车就启动了。


    一路无话到达杭州东站,然后骑车到浙大玉泉小区旁边著名的青支坞,andy推荐了一家店据说番茄鱼做的不错。吃下来感觉还不错,价格也比较实惠。


    然后在浙大校内留学生公寓住下。本来下午想出去逛逛但不期而遇的阵雨打消了我们的计划,天气预报说台风“森拉克”正在台湾登陆,不禁担心未来两天的天气,不过已经出来了,就且走且看吧。在房间一直呆到晚饭时间,吃完晚饭雨也停了。


    晚上的安排是爬龙井梅岭。夜晚的杭州骑车感觉很好,难得都是林荫道,东拐西拐,到后来就东西南北不分了,还好有人领路。:-)


    梅岭的爬坡不是太长,但也不短,在你到达极限之前就正好结束了,比较适合训练。第二天的爬坡才能真正检验你的爬坡水平的。说起来这也是我第一次骑车爬坡,虽然里程表已经超过5k公里了,---上海没有坡道啊!


    一路冲下来可要小心了,因为这一路车还是比较多的,再加上是夜晚,安全第一,几乎都是拉着刹车下来的。


    下来后开始夜游苏堤(白堤?就是长的那一条),虽然看不到白天的景色,但两边的波光浆影也别有意思。一路还有市民在跑步锻炼,生活在杭州真是件幸福的事啊。

     

    9/14 礼拜天 晴,时有小雨

    早上一早起来,马上赶到汽车西站乘车到昌化。由于没有走杭徽高速,而且昌化段还在修路,所以到昌化已经9点多了。稍稍整理之后出发。直奔煜岭关。

     

    煜岭关在浙江和安徽的交界线上。开始一路都是平路,骑到白果村已经11点多了,村民介绍“白果”就是杏仁,而且村里还有一颗千年杏仁树王。顺便去参观了一下。出白果村是一段8公里的爬坡,这是第一次考验,在加上临近中午,肚中空空,更是体力的考验。


    然后到达煜岭关下的一个小镇,在路旁找了个小店一人吃了一晚面。面里加了本地的一种辣酱,很香。


    吃完午饭,就开始爬传说中的煜岭关了。


    爬煜岭关感觉还可以,第一个冲上关口。一路上来虽然感觉很累,但没有精疲力竭的感觉,也不用中途休息。


    艰难的上坡之后就是很爽的下坡。一路冲下来创造了最高的数据纪录51.8。下坡过程中可以看到高峡深溪,但由于速度太快,也没有停下来拍照,小小的遗憾。


    现在是在安徽境内骑行。这边风景不错但路面质量让人不敢恭维,都是年久失修的道路。2点多到达三阳镇。穿过镇,左拐又向浙江方向进发。本来以为爬完煜岭关就结束今天的爬坡“赛段”了,没想到当地人告诉我们还要爬比煜岭关更高的一个岭。真是晕菜!一点心里准备都没有。开始担心能否今天到达威坪。


    真正的考验才刚开始!这是一个盘山公路,比煜岭关更长,更陡。似乎绵延得没有尽头。每一次幻想弯道的尽头就是终点,又每一次都被现实无情的击碎。速度已经降到10以下,而且小腿开始跳动。体力已经完全没有了,屁股疼得要命,只能靠意志在坚持。最后,终于缴械投降,停下车来休息。停下来一次就有第二次。在第三次停车休息时,看到lixie也上来了。得知他一直没有休息时,不禁佩服他的体力。


    一般来说无论平路还是爬坡我的速度是车队里最快的,齿比也稍微高一些。但这并不是说我体力最好,lixie以前练过长跑,他的体力实际比我强。爬坡时间长了,他就能超过我了。突然明白了,环法有爬坡王,冲刺王还是有道理的。


    差不多两个小时才爬上来。岭的尽头没想到是一个小镇,叫金川。在这里rp大爆发,尽然爆胎了。被一根铁钉直接穿透。后悔没有多带几个备胎,而且补胎技术也不行,最后还是一个本地小伙子帮忙才把胎补好。前前后后耽搁了一个多小时,提心吊胆上路已经5点多钟了。


    以后几乎都是下坡居多。途中lixie摔车了,因为过弯速度没有降下来,发生侧滑。幸好只是一点小小的檫伤。其实这已经是第二次出情况了,在下煜岭关的时候,henry的车也是因为过弯速度快发生了侧滑,不过还好及时纠正了过来。当时路边就是悬崖,现在想想真是后怕...


    金川到威坪可能有50多公里,但我们骑了20公里不到天就黑了.这里是山区,路边几乎没有人,而且温度也下降得很厉害.在又冷又饿的骑行中,每个人都在想今晚会如何度过.


    沿着盘山路下来,终于看到了一些灯光.这是一个叫"合富"的村庄.本来希望能找一个地方住宿一晚,但这里没有旅店.没有办法,只有夜行. 夜行是非常危险的,因为看不清楚路面, 而且这里还是山路,但我们当时感觉这边路况还不错,比较平坦,2个多小时到威坪应该问题不大. 没想到这段路出了这次最大的情况。


    这时已经下起了雨,我们分成两个group,前面是andy,lixiehenry, jingming和我在后面.其中只有andyjingming有前灯,但是jingming的前灯还不太亮。


    大约骑了几公里,雨越来越大,在一个下缓坡的路面,我们的速度可能在20左右,andy他们三个已经和我们拉开了约30米的距离,我和jingming有差不多56米距离的样子,突然我看到jingming一下子飞了出来,车也倒在了路旁。停车下来,我看到jingming已经躺在地上,表情比较痛苦。我把他扶起来发现手上有血,这个时候前面的andy也回过来了。情况还是比较严重的。有4处檫伤,而且手上虎口的伤口还比较深,好半天才止住血。lixie带来了酒精棉和创可贴。没有绷带,我把袜子剪了(没有穿过的*_^)


    现在回头想想,当时jingming没有头盔也没有手套,几乎没有任何保护设备。没有头部受伤和骨折实在是大幸。


    andy果断决定马上回头,推车回到了合富村。首先找到了医生包扎了伤口,医生说没有大问题。我们都松了一口气。然后又找到了村支书,一个热心的中年人,他让他老婆给我们做了晚饭,又腾了个房间给我们过夜。第一天行程终于结束,不过无论是过程还是结果都是我们都没有想到的。

     

    9/15 礼拜一

    早上合计了一下,lixiejingming乘车返回杭州,andyhenry和我继续骑行。


    从合富村到威坪这一段还是山区,气势比较雄伟,景色也很秀丽。到威坪后,转向千岛湖镇,这一路就是环湖公路了。这段路是理想的骑车路线。首先是路况好,能保持27以上,如果体力好的话平路保持30没有问题。第二是风景好,穿行于湖光山色之间,心情愉快。而且更绝的是间或还有隧道和少量的爬坡,想冲冲坡也有机会。要是没有第一天的高强度,骑这一段应该是比较休闲,比较惬意的。但因为第一天体力透支,而且当天气温也高了一点,所以骑到后面还是比较suffering.


    在这个过程中我还发生了一件比较囧的事情。我竟然把包丢在路边的一个候车亭了。发现的时候已经过了半个多小时。马上打的回去看到包竟然还躺在那里。以后不能再发生这种事情了。


    到淳安县城已经1点多。赶紧买了回杭州的大巴票。然后到KFC补充弹药。andy本来还打算到千岛湖边去玩玩水,但大家都累的动不了了,留待下次吧。


    下午410分的车回杭州。车还没有开出淳安城就下起了倾盆大雨,难到这就是传说中的台风“森拉克”?!不过我们也一点都不关心了。


    6点多到杭州,马上向火车站骑。在西湖边骑车发现杭州豪车真多,名不虚传。又看到西湖上面的月亮好圆好亮。下车随便拍了几张。


    杭州站自行车上火车一点问题都没有。再次在心里问候上海南站的装13男他家人。


    一路无话,到达上海南站,然后上地铁一号线到火车站站,出来后沿着周家嘴路平安到家。结束这次 中秋节千岛湖骑行。

     

  • 编程对测试人员意味着什么?

    2008-08-31 17:40:28

    编程对测试人员意味着什么?


    老毛说“不破不立”,从我个人的看法我是完全否定当前“编程是测试人员的必备技能”的说法和后面的逻辑,我否定把编程能力拔的如此之高的说法,这是“破”。 那么在这篇文章我要“立”,从我个人经验出发说说“编程对测试人员意味着什么?”

     

    首先要说,我并不是狭隘的“QA主义“者,也并不反对测试人员学习编程,提高编程能力。而是我们要对编程对测试人员的作用有一个清晰的认识。

     

    从我个人来说,可以说我一直以来就是编程能力的受益者。

     

    我这6年的工作中,从职位来说5年是在做QA,只有最开始的一年在做Dev,但一直以来我就没有停止过编程的工作。开始是用c/c++,然后是javaruby,现在用得比较多的是bash。我做过c51单片机程序,j2ee项目,用pythonruby开发过比较复杂的自动化测试系统。商业测试软件使用过robotqaload,等等。我写的代码质量丝毫不比一个普通的开发人员差。

     

    但是我并不打算学好编程技术而转行去做Dev,也并不是为了做自动化测试而学习编程。大部分的时候我的职位是一名黑盒测试工程师,我热爱这个工作,并且一直干得也很出色。只有一段短暂的3个月我是全职的性能测试工程师,但当回到黑盒测试的时候,我发现我依旧非常享受发现bug的过程。

     

    最开始的时候,我只是因为喜欢编程而编程,就像我喜欢测试而去做测试一样。所以我把大量自己的业余时间花在学习编程和软件设计开发上,后来我渐渐发现,编程能力也是软件测试的能力的一个重要方面,因为编程能力能让你更高效的测试

     

    即使你不是自动化测试工程师,也并不打算去做白盒测试,我仍旧强烈建议你学习一门通用的脚本语言,在ruby/python/perl中选一种,如果还有时间和经历,再学习一门通用的编译语言在c/java/c#中选一种。

     

    举一个例子,我现在测试的系统在安装好之后需要在命令行进行一些繁琐的配置工作,这些工作是重复而且容易出错的(我的记忆力不好)。后来我写了一个expect脚本来帮我完成所有这些工作,一个命令就搞定了。所以不但我节约了时间,而且我可以以最好的状态去开始真正的测试。

     

    这样的例子,太多了。毕竟,我们工作的对象和环境就是程序和程序构成环境,很多地方都有程序的用武之地。比如测试中需要一个包含100000个文件的目录。几行代码就能完成手工不可能完成的任务。

     

    追求更高效的测试是一个测试人员不断提高自己水平的动力之一,在这一点上编程能力真的有意想不到的作用哦。

     

    作为总结,我想说我对编程能力对测试工程师的作用的看法是,它很重要,但并不是核心的能力。它,是为了让我们更高效的发现bug,那才是测试工程师最核心的能力。
  • 编程是测试人员必备的技能吗?

    2008-08-31 16:12:11

    编程是测试人员必备的技能吗?

     

    现在经常能看到“编程是测试人员必备的技能”这样的观点被提出。支持它的理由是:编程能让你进入自动化或者性能测试领域,这样你才能成为一名高级的QA

     

    我要说这个观点和后面的逻辑都是完全错误的。

     

    首先自动化测试对工程师能力的要求和黑盒测试几乎完全不同。优秀的自动化测试工程师,并不必然就是优秀的黑盒测试工程师。实际上我更愿意把自动化测试开发看成软件开发的一种。

     

    其次,优秀的自动化测试工程师,更不是必然就是高级的QA工程师。在企业里,高级QA工程师的一般要具备下面的能力或知识:


    • 寻找bug的能力 ---- 最核心的能力,其实是综合能力的体现
    • 系统分析的能力 ---  主要在设计testplantestcase时候体现
    • 追踪问题的能力 --- devdebug一样,QA需要从一个最表面的问题追踪到自己能到达的最贴近问题发生点的地方
    • 宽广和深厚的技术背景  --- 操作系统,编程能力,网络等,各个企业侧重点不一样


    在企业里,人们希望高级工程师能负责起一个产品的测试,带领一个team完成从testplan到最终release给客户这个过程中所有QA需要完成的工作。

     

    请注意,编程能力只是测试工程师众多能力要求的一个,而且还不是核心的功能,更不是必备的。其次,我并没有列出行业背景知识。对于高级QA工程师来说,行业知识就像剑客手中的剑,--重要的是剑术,而不是剑。在这里要顺便鄙视一下面试里全是自己公司产品相关内容的公司。

     

    抛开上面所有教科书里对高级QA工程师的要求。一名高级QA工程师的工作实际上能增强Devmanager对产品的信心,能带动整个QA team的测试效率和激情。总之,他的工作是专业的,不可替代的和值得尊敬的,和常规印象里对黑盒测试工作的“低级,没有技术含量”的印象完全不同。

     

    所以,

     

    如果你只是被月薪XXX这样字样吸引进入软件测试行业,那么我要给你泼冷水,因为初级测试人员的工资肯定低于初级开发人员。

     

    如果你是Dev并因为某种原因被迫转到QA,但并不屑于干“简单,没有什么技术含量”的黑盒测试,那么你完全可以马上转到自动化测试,那里你可以重新找到coding的快乐。

     

    如果你是测试培训机构,那么我要说,忽悠吧,继续忽悠,你的QTP培训班生意肯定会更好。

     

    但是,如果你真的热爱QA这个行业,真的想成为一名受人尊敬QA工程师。那么抛开这些眼花缭乱的浮云,放低自己的心态,踏踏实实从一名黑盒工程师干起,你会在成长的过程中体会到QA工作给你带来的乐趣,收获你的工作为你带来的价值。
  • 软件测试并不仅仅是按照testcase测试

    2008-07-12 16:42:17


    软件测试并不仅仅是按照testcase测试
    有一种普遍存在的看法是 软件测试 只是一个没有什么技术含量的工作,任何人只要能读懂testcase就能做软件测试。或多或少地,在我工作过的每一个公司都有人这样的观点,特别是规模小的公司更甚。

    当然,这是一种完全错误的观点。

    如果我们把软件看做是一个圆球,那么软件测试的目标就是尽可能的覆盖最多的球体表面。。

    所有的testcase的集合可以看做是一张试图包住整个球体的网,而一个testcase就是网上的一个节点。可见对于这张网来说,最重要的不是它的节点的数量而是节点的布局。testcase应该覆盖整个球体表面,但也不应该有太多的节点堆积在某一个区域。

    一个良好设计的testcase集合需要对软件的深刻理解,很高的抽象能力,还要在覆盖率和可执行性之间保持平衡。对这些能力的要求,相比于其他的设计工作,比如软件设计,并无二致。

    如果说testcase本身只是一个节点,它并不能覆盖更多的区域,那么一个测试人员实际的测试行为就像一块在围绕在点周围的布,才能填补网格中空白部分。有多大区域能被测试行为所覆盖,这是一个衡量测试人员能力的关键要素。

    好的测试人员在测试的时候所做工作远远超过testcase本身。实际上,这也是对测试人员的一个基本要求。测试人员应该通过各种方式扩展testcase,比如改变参数,调整前置条件,从多个角度来观察系统行为,使用不同的方法等等来尽力覆盖更多的内容。

    研究显示,在一个项目中,超过3/4的bug并不能仅仅根据testcase的descrīption得来。那也就是说,一个好的测试人员相对于一个仅仅根据testcase来测试的测试人员,其发现的bug数可以是后者的4倍之多。

    所以软件测试的工作也许看起来简单和直接,但事实是,实际的工作远远超过testcase本身。

    以下是本文的英文版。(following is the English edition)
    =========================================================
    Software Tester Offers More Than Just Test Cases

    Some people think that software testing is a low skill job, and that just any one can be a tester.  This is definitely not true.  Allow me to explain why.

    If we represent the software being tested as a ball, then the aim of the software testing is to cover as much of the space of the ball as possible.

    Test cases act together as a net, attempting to cover the ball.  Test cases act individually as a node in that net.  So the most important aspect of a test case is not its amount, but its structure.  The test case should cover the entire surface of the ball, but without too many nodes in any one place.

    A well designed test case requires a deep understanding to the software, high ability of abstraction, and skills to balance between the coverage and testability.  The requirements are not that different from other forms of design work.

    To continue the previous analogy, the actual test behavīor is like a piece of cloth wrapped around the node; there to fill spare space left by nodes.  How much space your real test behavīor can cover is one key standard to measure the capability of a tester.

    Good testers test far more than the test case descrīption.  In fact, it’s an essential requirement.  They will extend the test case descrīption by changing parameters, adjusting preconditions, and using many different means in order to try to wrap more space around a single test case.

    One investigation showed that over 3/4 of all bugs found, are not directly related to test case descrīptions.  That is to say, the number of bugs a good tester can find can be 4 times as many as that of a tester who simply follows the test case descrīption.

    So the job of software testing may seem simple and straightforward enough, but the truth is, the actual effort expended is much greater than just a simple test case.

    (Thanks to Kyle for fixing errors of the original version)
  • Everbright, a tool kit helping build up test with Watir, hosted in Rubyforge.

    2008-05-10 19:22:34

    I'm glad to announce that a project "Everbright" has been lauched in Rubyforge aiming to provide a tool kit by using which it can become easier and more efficient to build up test with Waitir from scratch.

    As we know, Watir is a great library, but it does not mean to be a framework, a switss knife, an another "QTP". So a lot of extra assistant work must be done if you are going to test a web site with Watir, such as Loging, Reporting, handling xls document, etc.

    Yes, that' is exactly what Everbright will bring to you. Everbright is a collection of classes/utilities I wrote to resolving problems in my previous projects, and I'm sure very likely you will meet them again.

    Try it and enjoy Ruby&Watir. You are welcome to contrribute your code.

    The project url: http://rubyforge.org/projects/everbright/



  • vimrc

    2007-12-19 09:51:12

    set nocompatible
    source $VIMRUNTIME/vimrc_example.vim

    "source $VIMRUNTIME/mswin.vim
    "behave mswin

    "-----------------------------------------
    " tab and indent
    "-----------------------------------------
    set softtabstop=4
    set shiftwidth=4
    set expandtab
    set smarttab
    set autoindent

    colorscheme darkblue

    "-----------------------------------------
    " edit
    "-----------------------------------------
    set ruler
    set backspace=2
    set nowrap
    set number
    set lbr
    set tw=500

    "quickly move cross/delete word in insert mode
    imap <C-Left>   <C-o>b
    imap <C-Right>  <C-o>w
    imap <C-BS>     <C-o>db
    imap <C-Del>    <C-o>dw

    map <C-Return>  $<Insert><CR><ESC>      

    "-----------------------------------------
    " search
    "-----------------------------------------
    set is
    set ic
    set hlsearch
    "set noignorecase
    nmap <F2> :nohlsearch<CR>


    "-----------------------------------------
    " move
    "-----------------------------------------
    " scroll
    map <c-j> <c-y>
    map <c-k> <c-e>

    "-----------------------------------------
    " tag
    "-----------------------------------------
    "taglist
    nnoremap <silent> <F8> :TlistToggle<CR>
    let Tlist_Show_One_File = 1

    "for develop everbright
    "set tags=c:\\ruby\\lib\\ruby\\ruby.tags,d:\\CVSProject\\projects\\app_testing\\auto_test\\main\\bin\\everbright.tags

    "-----------------------------------------
    "edit vimrc
    "-----------------------------------------
    map <F11>       <ESC>:edit $VIM\_vimrc<CR>
    map <F12>       <ESC>:source %<CR>

    "-----------------------------------------
    " buffer
    "-----------------------------------------
    set hidden

    map <C-Tab>     :bnext<CR>
    imap <C-Tab>    <ESC>:bnext<CR>
    map <C-S-Tab>   :bprevious<CR>
    imap <C-S-Tab>  <ESC>:bprevious<CR>
    map <C-D>       :w<CR>:bdelete!<CR>
    imap <C-D>      <ESC>:w<CR>:bdelete!<CR>

    "-----------------------------------------
    " leader command
    "-----------------------------------------
    "shotcut with mapleader
    let mapleader=","
    let g:mapleader=","

    nmap <leader>w :w!<cr>
    nmap <leader>f :find<cr> 
    nmap <leader>bn :bn<cr>
    nmap <leader>bp :bp<cr>
    nmap <leader>bd :bdelete<cr>

    " with 'dd', to add/delete new line in normal mode
    nmap <leader>o  A<cr><esc>
    nmap <leader>O  I<cr><esc>

    "-----------------------------------------
    " abbrevs
    "-----------------------------------------
    "general abbrevs
    iab xdate <c-r>=strftime("%Y-%m-%d %H:%M:%S")<cr>


    "-----------------------------------------
    " autocmd by FileType
    "-----------------------------------------
    " run scrīpt. not work. why?
    autocmd FileType vim    nmap <buffer> <F12> :w!<cr>:source %<cr>
    autocmd FileType ruby   map <buffer> <F12> :w!<cr>:!ruby %<cr>

    "-----------------------------------------
    " others
    "-----------------------------------------
    set nobackup "no backup. that's ~file
    set autowrite
    set go-=T "remove menu and boolbar
    "auto change dir to the file currently being edited
    set autochdir

    map <F5>        <C-l>

    "favourity filetypes
    set fileformats=unix,dos,mac

    "no sound on errors
    set noerrorbells
    set novisualbell
    set t_vb=

    "format statusline
    set statusline=\ %F%m%r%h\ %w\ \ CWD:\ %r%{getcwd()}%h\ \ \ Line:\ %l/%L:%c

    "-----------------------------------------
    " functions
    "-----------------------------------------
    set diffexpr=MyDiff()
    function MyDiff()
      let opt = '-a --binary '
      if &diffopt =~ 'icase' | let opt = opt . '-i ' | endif
      if &opt =~ 'iwhite' | let opt = opt . '-b ' | endif
      let arg1 = v:fname_in
      if arg1 =~ ' ' | let arg1 = '"' . arg1 . '"' | endif
      let arg2 = v:fname_new
      if arg2 =~ ' ' | let arg2 = '"' . arg2 . '"' | endif
      let arg3 = v:fname_out
      if arg3 =~ ' ' | let arg3 = '"' . arg3 . '"' | endif
      if &sh =~ '\<cmd'
        silent execute '!""C:\Program Files\Vim\vim70\diff" ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3 . '"'
      else
        silent execute '!C:\Program" Files\Vim\vim70\diff" ' . opt . arg1 . ' ' . arg2 . ' > ' . arg3
      endif
    endfunction

  • bash learning

    2007-12-19 09:43:39

    这两天读了 Advanced Bash scrīpt Guide和shell 十三问。有一些有意思但以前自己不懂或混淆的东西。记下来如下。


    *) local,在函数内部定义有限作用域的变量
    > function foo { A=aaa; echo $A;  }
    > A=bbb; echo $A; foo; echo $A
    bbb
    aaa
    aaa

    > function bar { local A=aaa; echo $A; }
    > A=bbb; echo $A; foo; echo $A
    bbb
    abc
    bbb

    *) {} and ()
    {} like a anonymous function
    () commands in () will be executed in subshell
    > A=aaa; { A=bbb; }; echo $A
    bbb
    > A=aaa; ( A=bbb; ); echo $A
    aaa

    *) (())和let,整数计算
    > a=1
    > ((b=a+1))
    > echo $b
    2

    *) 子进程与父进程的变量访问
        1)子进程可以 看到 父进程的变量,因为它有父进程变量的copy
        2)子进程不可以 访问 父进程的变量
        3)如果要让 子进程 可以访问父进程的变量,那么父进程要export该变量
        3)父进程既看不到也不可以访问 子进程的变量。

    *) source(或 .) 会在当前进程里执行,就象在命令行输入的一样

    *) 管道会以子进程来运行

    *) "-"可以替代 “标准输出”或标准输入“
    它在管道中特别有用,可以避免管道broken,比如
    > echo "xxx" | cat -

    注意,"-"是由应用程序解释的(这里是cat),而不是bash

    *) 退出码
    0表示true,其他都为false


    *) CTRL 命令
    ctrl+c terminate a foreground job
    ctrl+z pause a foreground job

    ctrl+d 1) log out. similar to 'exit', 2) EOF, used in inputing HERE doc
    ctrl+g bell beep
    ctrl+l clear scree. similar to 'clear'
    ctrl+s freeze STDIN
    ctrl+q resume STDIN
    ctrl+u erase a line of input, from cursor to begin point


    *) 对${}的扩展
    一般来说${varName}是对变量的引用,但bash在此基础上提供了一些对字符串处理的扩展。

    替换
    1) ${varName/src/dst}是对变量字符串的替换,把第一个src用dst来替换
    2) ${varName//src/dst}是对变量字符串的替换,把所有src用dst来替换

    子串
    ${varName:pos}
    ${varName:pos:len}

    ${#varName} 取得字符串长度


    *) echo的参数
    -n 不要换行
    -e 可以使用'\'转义
        \a      bell beep
        \n      new line
        \t      tab
        \123    octal
        \x123   hex

     

  • testcase的写法,重于"形"还是重于"意"

    2007-11-17 08:55:30

    QA已经4,5.看到的testcase也不少了.有自己写的有别人写的.testcas的风格很变化多端,有些步骤详细得让一个新人都可以没有任何困难得跑一遍,有些呢,可能仅仅是一段描述的语言加上一个matrix,精炼得让第一次跑它得人无从下手.

    那么到底有没有一种最优得写testcase得策略呢?

    现在这个公司得做法给我了一些启示.它得testcase有两个特点
    1) testcase
    没有细节得描写.也就是说它重""得表达.

    testcase的任务是说明:做什么(summary),怎么做(steps), 得到什么(verify).在怎么做的描述上,尽量避免对细节的,特别是UI细节的描述.

     

    这样的好处是 testcase的表达更清晰了,避免了淹没于细节之中,第二个是可维护性增加了,特别说细节界面得修改不会导致testcase修改.

     

    这种风格的testcase第一次跑很困难,但以后就心领神会了,"只需痛苦一次"

    2)
    有很多testcase是模版+matrix自动生成得
    可能设计者觉得,步骤表述加matrix简单的结合显得指导性不够,那么用一个模版+matrix,按照排列组合的方式生成testcase可以一定程度弥补不足.

    使用这种方法.testcase的维护性大大提高,而有不会太多的损失testcase的指导性.
  • 再见锐柯:别了,金桥的船

    2007-09-29 11:33:46

    湖光荡漾,绿树匆匆,柿子红了,杨柳飘飘。引三五朋党,闲庭信步,看水鸟剪影于小岛building之间,轮卵石跳跃于湖面波光之上。斜坐木椅之上,高谈阔论,微风扑面,鸟语花香。各位,这不是公园,这是我们中午午餐后游湖的真实写照。

    有人说,有了水,风景才有了灵性。在上海这个寸土寸金的地方,金桥软件园竟然在园区中间有一个人工湖。怎一个NB了得。

    回头想想以前吃了午饭在电脑前发呆的场景,恍如隔世啊。

    一直就观测到湖边停了一艘小船,但从没有看到有人使用,此船何用?是不是软件园免费提供给大家游湖用的呢?那怎么没有人上去划船呢?终于有一天,咱们再也按耐不住,登得船来。

    在水上和在水边是完全不同的。一个是静止的看,一个是悠闲的划。粼粼水波,是那么的近啊。旁人羡慕的目光,让我们更是得意,湖面的空气,更清新,湖面的风,更轻柔,湖面的太阳,。。。。更晒人啊。还好,可以划到湖心小岛的后面,森森凉意扑面而来,沁人心脾,这里是水鸟的家,和它们问个好吧。

    突然,吆喝四起,狼奔豕突。原来是保安杀到了。没办法,弃船走人吧。以后在也没有机会划船了吧?

    别了,金桥的船。

  • 再见锐柯:土法炼钢

    2007-09-29 10:50:43


    大公司做什么都是有板有眼,讲究流程。甚至锐柯专门有个Team就是搞流程相关的东西。佩服一下先。不过对我这样从小,中型的IT公司出来的人来说,有点不以为然:繁文缛节何其多也?!

    来公司一个月后,终于有活干了。做一个性能测试项目,而且还只有我一个人做,但后期需要别得team合作。兵马未动,plan先行。Manager说你搞个schedule吧。行,怎么做我心里也基本有数了,excel里填了几行把大概的阶段写在里面,发过去了。

    “你这个就是土法炼钢!“,一句话把我的schedule打回来了。然后乖乖的装上Project,细细谋划起来。几经折腾,最后发现原来一个schedule里面包括这么多内容啊。

    写代码,写文档,培训,试运行,准备环境,安装环境。。。。什么时候做什么事,全得写上。即使开发阶段也要写明那段时间实现那些功能。我抱怨“这些进度根本就是未来的事,未来的事怎么说得准呢?“, “也许现在定的时间并不准确,但这是一个基础,项目进行中可以调整。但没有这份文档,怎么调整?“。说得有道理哈,不愧是Manager。

    终于project schedule写好了,然后纠集几个人review一下,存档。前后花了几天时间,值得吗?
    虽然自己是散漫得人,对这种详细计划的东西比较天然的抵触;但做了第一个schedule后,对“计划“有了更多的认识。在做schedule的过程中,真的也能想到一些漏掉的事情。比如有些事要和别的team配合的,那么早点写出来,通知他们,比自己事情做好了,再去通知他们,等他们准备好了,再进行下一个步骤效率要高。提高效率是我最感兴趣的东西。这一招以后也要用下去。

    再来说做得很好看得schedule是给manager或boss看得。我们engineer是干活的,所以任务下来,脑筋一下子就跳到怎么做,用什么技术…,但怎么干Manager是根本不感兴趣的,能不能按时完成,多个项目间配置资源等才是他感兴趣的。所以详细的schedule能帮助他了解,掌握项目的进度。

    当然,我也觉得,有些东西还是不能安排太细。太细的安排往往都是要改动的,而且实行起来也繁琐,比如做一点点事,就要去修改或填充schedule,最终只会做了很多工作然后一次行填完了事。这样的schedule就是形式主义了。“形式主义害死人啊“,要不得。Schedule的粒度要适中,特别是多人,多team的事务安排是它的长处,可以充分利用。

    当然,以前一个人做什么事也有个大致计划,但这个计划自己心里清楚就行了,不必写出来。别人就看你一天忙来忙去。突然有一天,“嘭“,盖子掀开,所有的东西都做好了,任务完成,变魔法一样。这样的风格在锐柯这样的大公司是行不通的。

  • 再见锐柯:离开Kodak,难舍叶莺

    2007-09-29 10:03:48


    昨天下午在HR那里领到了退工单,正式结束了在锐柯短暂的3个月。下个月长假结束就要去另外一个公司报道了。

    离开总是有点伤感的。想想7,8,9这一年中最火热的三个月,真是非常丰富,充实,Happy的3个月。锐柯,金桥软件园,Kodak,新金桥21楼,午餐后的游湖,乒乓球赛。。。当然还有新结识的朋友们。
    锐柯是Carestream Medical Group在中国的全资子公司,我所在的R&D Center承担了Carestream多个项目,看的出来他的重要性还在不断提高,象所有别的跨国企业一样,越来越多的研发工作都转移到了中国。如果你并不熟悉“锐柯“这个名字的话,并不奇怪,因为他在2007年的5月才刚刚成立,而在之前他的名字是Kodak Medical Group.

    提到Kodak,这个胶片时代的巨人在数码相机席卷全球的潮流中似乎没有发出它应有的强大的声音。确实,Kodak现在正处于一个数码转型期,它的未来方向是数码出版业。转型力度之大,不要说越来越利润微薄的相机业务,甚至连利润巨大的Kodak Medical Group都转卖给Onex,一家加拿大的企业集团。

    有100年历史的Kodak,在之前,我的印象里只是红黄色的胶卷和遍布城乡的快印店。进了锐柯,我才慢慢体会到强大的Kodak企业文化,对于这样一家有深厚底蕴,强大文化的公司,或许在市场上它有了起落,但我相信所有的低迷都是暂时的,它肯定能不断获得发展。我很遗憾我不是一个Kodak员工,但锐柯,一个Kodak已经出售的公司,公司里弥漫的Kodak气氛还是令我向往。Kodak,毫无疑问是我经历过的最令我尊敬的公司。希望锐柯能吧Kodak的文化继承下去。

    有一个插曲,刚进锐柯2周,第一财经做了一个叶莺女士的专访。叶莺谈了Kodak的转型之路。充满个人魅力得叶莺被人称做“柯达女神”,谈到Medical Group和Kodak正式分离,员工们送它的礼物上写到“离开柯达,难舍叶莺”时,潸然泪下。在那一刻,我也深深感动了。如果一个公司员工和老板有这么真挚得感情。公司怎么不会一条心做好每一件事情。一个公司人人一条心,又有什么事情做不好呢?在那一刻,我也在心里默默说:Kodak,一路走好!

    说起来,Kodak是我经历过的第一个世界500强。一个公司要做到这么大,还能保持健康的运转,我体会到一定要有强大的企业文化。强大的企业文化才能凝聚人。凝聚人不仅仅是钱。中国企业加油吧。

    Kodak, building 8




    Carestream Building4

  • QALoad: 在中文环境录制utf8编码的xml request

    2007-08-23 22:32:12

    但是如果locale设置为China,那么QALoad录制的脚本将是是GB2312编码的。也就是说,QALoad在拼接字符串的时候,如果字符串里面有中文,那么它是GB2312编码的。比如
        CLoadString buf;
        const char* str = "abc汉字def";
        buf += str;

    在这里str是GB2312编码,长度是3+2+2+3 = 10;

    如果在脚本里拼接了一个xml request的字符串,且里面有中文,那么问题就出现了。字符串是用gb2312编码的,但实际上一般来说,xml request/response都是utf8编码的。这个时候就需要做从gb2312到utf8的编码转换。

    关于ANSI编码(GB2312是ANSI编码的一种)和Unicode编码问题的一篇很好的文章:http://www.regexlab.com/zh/encoding.htm

    这个编码转换需要一个叫conv的lib,在这里下载 http://gnuwin32.sourceforge.net/, 下载安装到目录假设为$install
    1. 把$install/bin/libiconv2.dll拷贝到C:\WINNT\system32,
    2. 把$install/include目录加入到 c++ compiler include. 访问途径Menu: Option->C++ Compiler Option
    3. 把$install/lib/libconv.lib加入到c++ compiler library. 访问途径Menu: Option->C++ Compiler Option

    转换实例代码如下
     char * xmlStr = "....";//xmlStr contains the xml to be sent, GB2312 encoded.
     unsigned int ilen = strlen(xmlStr); //input buffer length
     unsigned int ōlen = ilen *  2; //output buffer length

     char * utf8XmlStr = (char *)malloc( olen); //acquire output buffer
     memset(utf8XmlStr, 0, olen);

     //duplicate an output buffer pointer, 
     //because pointer value will be chaneged in function "iconv"
     char* utf8XmlPtr = utf8XmlStr;
     iconv_t cd = iconv_open("utf-8", "gb2312"); //gb2312 -> utf-8
     iconv(cd, &xmlStr, &ilen, &utf8XmlPtr, &olen);
     iconv_close(cd);
    free(utf8XmlStr);
    utf8XmlStr=NULL;

       

  • 关于C语言的sizeof

    2007-08-16 15:07:43

    关于C语言的sizeof

    今天用c语言写一个函数需要遍历传递进来的一个 数组.显然这种情况需要知道数组的大小. c语言的sizeof行不行呢?网上搜索到一篇有意思的讨论的文章http://bbs.chinaunix.net/viewthread.php?tid=666403&extra=&page=2.从这篇文章还不能得到答案,然后写了一段测试代码测试一下.在VC6, winxp, x86系统上

    void foo(int ia[]) {
     printf("size = %d", sizeof(ia)); // 4
    }

    void test11() {
     int ia[] = {0,1,2,3, 5,6,7,8,9};
     printf("size = %d\n", sizeof(ia)); // 40 = 4*10
     foo(ia);
    }

    在这里,系统给出了不同的sizeof值.从这个现象可以得到下面一些结论
    1) sizeof的值是 编译时 确定的.确定的依据就是sizeof里面symbol的类型.c/c++是强类型的语言.所有的symbol在编译时都是确定的.
    2) 显然c的pointer本身并没有携带任何数组长度信息.所以foo和bar函数里,打印出结果是4而不是40.

  • 关于c++和其他一些语言的废话

    2007-07-27 11:03:25

    关于c++和其他一些语言的废话

    我的语言学习历程是这样的,最开始在大学里学习c,然后自然发展到c++。c语言做过比较大的项目,开发单片机上的驱动。c++没有做过大项目,当时觉得学得还不错了,现在回头看,除了设计方面不说,即使c++语言本身,也有很多地方也没有搞清楚。

    大学毕业一年后,开始转到Java。java是一门无论语法还是库得设计都很清晰的语言,Java特别适合开发大型程序。它的这些优点都说的太多了。在它这个级别,可能c#是唯一的对手,不过我对c#还一无所知。

    这几年,也学习了一些脚本语言,用的最多的是Ruby和Javascrīpt。我个人观点是,Ruby是脚本语言里设计最好的语言,当然相比perl和python它出现最晚。Ruby的语言我觉得有两个特点最让人赞叹
    1)核心小而精干,想想一个事实是,它的private和public竟然都实现为一种函数,而不是语言本身的内在特性。这就使得在它上面添加新的特性比较容易,不会侵入语言核心。
    2)Ruby可能是脚本语言里面对lambda支持最精彩的,lambda本身的特性使得很多问题有了优美的解决方式。想想它的Collection库。

    相对于Ruby,perl的优势是互联网上庞大的library,但它不愧号称hacker的语言,语法实在是不敢恭维。

    Python最大优势是“看上去更简单的语法”。但这点优势也在被它自己慢慢丢弃。看看它不断往语言里面加入的东西。

    在Web client端运行的语言你几乎没有选择,只能是javascrīpt。不要对我说还有VBscrīpt,我认为VB这样的语言在这个世界大行其道简直是一个奇迹,一个MS用它的垄断和金钱砸出来的一个变态的奇迹。javascrīpt据说是最被低估的语言,c的语法外衣,函数式语言一样的动态特性。javascrīpt可以写出一个c程序员永远想不到的代码样式,看看prototype库。我建议我们都用prototype库,用它的风格写代码。一个ruby程序员会发现它非常熟悉。:)

    对函数式设计语言也有相当的兴趣,这是一个完全不同的世界,我还是初学者。对一个语法完美主义者来说,scheme肯定是最佳学习选择,但实用的机会不多。能接触到的最多的是emacs的elist和autocad的visual lisp。这些场合的lisp都是作为象sh一样的脚本调用application环境的命令,不知道高阶函数和延迟求值这些特性做应用开发能不能用上。

    说了这么多废话其实都是因为这几天又重新学习c++,总是把c++和java对比,感触很多。最主要的感觉有两个,
    1)c++太复杂。它支持4种风格的设计:c语言风格,抽象数据结构(Abstract Data Type), 面向对象设计和范型程序设计。单独的每一种都不算复杂,但要支持了4种风格,不可避免的c++成为一门复杂的语言。听说它的设计者都不指望人们能完全弄懂它。我想对应用者来说我应该,不排斥任何一种,但尽量使用最基本最简单的东西。在某种实现方式可能变得复杂或使用高级技巧的时候,保持警惕,宁可多写一些简单的代码,而不要”通用“但”精妙“的代码。

    2)内存管理。内存管理可能永远是c/c++程序员的恶梦。为人称道的Loki的smartpointer可能设计很高妙(其实我并没有真正读懂),但我认为它使用了对我来说太复杂的技术。我的原则是首先考虑在栈上申请对象,因为系统会为我释放对象,如果要在堆上申请对象,那么设计一个factory,在同一个地方申请和释放对象。
  • 换新工作了

    2007-07-23 15:11:02

    这个月1号开始在新公司开始上班。3周过去了,主要看看他们以前开发的自动化框架和学习工具。

    大公司,microsoft的技术平台,商业测试工具,严格的流程。。。太多太多和AR不一样。不过这些正好是我现在经验里缺少的。

    在上一个公司呆了3年。出来了,发现外面世界也很精彩。

  • 使用QALoad做性能测试简要介绍

    2007-07-23 14:52:55

    使用QALoad做性能测试简要介绍

    1 引言 
    2 产品组成 
    2.1 Scrip Development Workbench 
    2.2 Conductor 
    2.3 Player 
    2.4 Analyze 
    2.5 协同工作 
    3 典型的工作流程 
    3.1 录制脚本 
    3.2 编辑脚本 
    4 脚本特点 
    4.1 Transaction 
    4.2 DataPool 
    4.3 Checkpoint 
    4.4 计数器 
    4.5 Verify 
    4.6 Validate 
    5 配置Session 
    5.1.1 Test Information 
    5.1.2 scrīpt Assignment 
    5.1.3 Machine Configuration 
    5.1.4 Monitoring Options 
    5.1.5 Machine Assignment 
    6 Analyze 
    6.1.1 报告的基本模式 
    6.1.2 具体的报告介绍 


     
    使用QALoad做性能测试简要介绍

    1 引言
    QALoad是一个主流的商业的性能测试工具(据说是最好的性能测试工具)。因为它是我使用的第一个商业的性能测试工具,所以对它的功能,我无法给出一个和同类产品比较的结果。而只能说说我自己的认识和感受。
    从我个人初步使用经验来说,QALoad功能强大,且概念清晰,易于理解,配套设施也很完善。


    2 产品组成
    QALoad从产品组成来说,分为4各部分, Scrip Development Workbench,Conductor,Player, Analyze。

    2.1 Scrip Development Workbench
    这个可以看作是录制,编辑脚本的IDE。它支持的协议包括WWW,数据库访问等等。录制的动作序列最终可以转换为一个cpp文件。

    2.2 Conductor
    对于脚本运行时的配置,由Conductor负责。对于实际的一个测试,特别是性能测试,下面一些细节都需要确定
    · 部署在那些player上面
    · 有多少虚拟用户(virtual user)
    · 每个用户运行多少次Transaction
    · 等等
    QALoad把所有这些配置数据用一个概念来表达: Session.并可以存在一个以ID结尾的文件里。这样,对于负责的配置,可以一次配置,多次使用。

    2.3 Player
    Player就是一个Agent,一个运行测试的agent,可以部属在网络上的多台机器上。

    2.4 Analyze
    Analyze是测试结果的分析器。它可以把测试结果的各个方面展现出来。

    2.5 协同工作
    总的来说,这4个工具工作起来大概是这个样子,箭头表示文件的传递。

    1. workbench 产生测试脚本,cpp编译后的dll文件
    2. conductor产生一个session文件,里面 保存了player信息和dll信息
    3. conductor执行一个session,把dll交给player来运行
    4. player执行dll,产生一个timing文件
    5. conductor把所有player产生的timing文件交给Analyze分析
    6. analyze生成各种报表,把测试结果展现给用

    3 典型的工作流程
    对开发者来说,一个典型的工作流程是这样的:
    · 在workbench里录制脚本,然后根据时间测试的需要修改录制的原始cpp文件。最后编译cpp文件为dll文件;
    · 在conductor里,配置一个test session
    · 在conductor里,执行此session。执行文件会自动发送到player那里执行。
    · 执行完毕后,conductor会自动启动analyze来分析此次执行的结果

    3.1 录制脚本
    商业的自动化测试工具都把 易用性作为卖点。所以录制过程是相当的简单。以WWW协议为例(本文档都以WWW协议为例),点击 录制 按钮后,它会自动打开IE,然后你在IE上完成所需要的步骤,点击 停止按钮就可以了。


    一个录制过程的结果是一个capture文件(以cap为后缀名)。对开发者来说Capture文件没有什么用。它的作用是转化为visual tree文件(以vistree为后缀名)。

    转化命令在capture文件条目上的右键菜单里。转化的结果是两个同名的文件,一个vistree文件和一个cpp文件,比如xxx.cap转化为xxx.vistree和xxx.cpp.

    Visual tree文件的目的是,把测试脚本的流程 (包括步骤和验证等) 用一棵可视化的树来表现。这种功能的动机是可以理解的,但如果你熟悉了它的机制,并且测试逻辑比较复杂,很显然,直接编辑代码会方便得多。


    在这里,我建议不要直接修改xxx.cpp,因为workbench会假设xxx.cpp和xxx.vistree在内容上是一致的,并且如果你在vistree上操作的话,workbench会自动维护二者的一致。如果二者存在不一致,可能会发生问题。所以,如果你要编辑自己的cpp文件,最好还是从xxx.vistree创建另外一个cpp文件,比如yyy.cpp.

    在workshop中,双击打开xxx.vistree,然后在右边的tree的任意一个节点上点右键,选择”Create Editable scrīpt File …”


    3.2 编辑脚本
    QALoad测试脚本具有下面的特点
    1) 脚本语言是c++语言;
    2) 对每一种协议,QALoad提供了一些协议相关的函数,使得在此协议上的工作更容易。比如对于www,QALoad提供了Navigate_To来发送一个到Server的Get请求;
    3) Transaction。Transaction是QALoad测试脚本运行和结果分析的核心,在下面有详细的介绍。
    4) QALoad提供了几种机制来让你更好的完善测试脚本,其中重要的包括

    数据池(datapool)
    计数器
    checkpoint
    Verify


    对于具体的协议来说,相应的操作函数在manual里有详细的介绍,这里无需多言。

    4 脚本特点
    下面分topic介绍一些重要特点的使用方法和注意事项。

    4.1 Transaction

    1) 一个测试脚本有且只能有一个transaction;
    2) 所有的需要测试的步骤都必须组织在transaction里面;
    BEGIN_TRANSACTION();
    //your test logic code
    END_TRANSACTION ();
    3) 虽然在脚本里看上去transaction只会运行一次,但实际上在配置session时,你能够定义transaction被多次执行。
    4) Transaction里的错误处理有三种方式
        a) Continue。就当没有发生,继续执行下一行代码
        b) Abort。Transaction立即退出,执行此transaction的虚拟用户也随即退出
        c) Restart。跳转到transaction的清理部分执行,然后开始下一个transaction。这种方式只有部分协议支持,WWW是其中之一。

    注意,对于Restart方式,首先在scrīpt里需要加上clean up的代码,RESTART_TRANSACTION_TOP(); RESTART_TRANSACTION_BOTTOM(); 然后在Conductor里配置Session时,需要指定使用 运行时 使用Restart方式处理异常


    4.2 DataPool
    数据池可以让你把scrīpt和测试数据分开。Datapool支持两种形式
    1) Central Datapool
    数据文件放在Conductor机器上。Player需要它的时候,向Conductor索取。注意,对一个测试脚本来说,只能使用一个Central Datapool。
    2) Local datapool
    存放在player所在的机器上。一个测试脚本可以使用最多64个datapool文件。

    配置并使用Datapool的过程
    1) 创建datapool。
    Workbench menu: File->New->Datapool
    Datapool就是一个Matrix。比如创建一个两列的datapool,第一列命名为username,第二列命名为password。
    2) 使用Datapool的代码
    a) Central Datapool

    BEGIN_TRANSACTION();

     GET_DATA(); 
     char *name = VARDATA(1);
     char *pswd = VARDATA(2);
     …
    END_TRANSACTION();


    b) Local Datapool

    #define DP_ACCOUNT 2 /* Identifier for a datapool file*/
    OPEN_DATA_POOL("scuser.dat", DP_ACCOUNT, TRUE);

    BEGIN_TRANSACTION();
     …
     READ_DATA_RECORD(DP_ACCOUNT); // Read one record.
     char* name = GET_DATA_FIELD(DP_ACCOUNT, 1); //read col 1
     char* pswd = GET_DATA_FIELD(DP_ACCOUNT, 2); //read col 2
     …
    END_TRANSACTION();

    3) 在conductor里为session配置datapool
    Conductor Tab:scrīpt Assignment->External Data.

    问题:如果使用Local Datapool,在测试运行时,conductor是否会自动把datapool数据文件copy到player所在的机器?

    4.3 Checkpoint
    Checkpoint用来收集执行某段代码的时间。Checkpoint分为自定义checkpoint和自动的checkpoint


    对于自定义的checkpoint,它的使用非常简单
    比如:
     Char *url = http://xxx/login?user=user1&pswd=pswd1;
     BeginCheckpoint("Login");
     Navigate_To(url);
     EndCheckpoint("Login");

    在运行时,执行chekcpointer之间的代码的时间被精确的统计。


    自动的checkpoint是对QALoad自己定义的函数,比如上面提到的Navigate_To,自动生成的checkpoint。你可以用 Set (NEXT_REQUEST_ONLY, CHECKPOINT_NAME, "get logo pic"); 来给下一个自动checkpoint命名。


    我建议尽量使用自定义checkpoint。

    4.4 计数器
    在QALoad里,计数器是一个很有用的概念。Counter的作用是收集运行中的一些数据,在分析测试结果时,在Analyze中可以很方便的把counter的数目查询和显示出来。在Analyze中有一个counter面板,里面可以查看所有的计数器。


    QALoad自己也使用了很多计数器。比如“功的Transaction数目”就是用counter来计数的。


    使用counter非常简单,只需要下面两个函数(宏), DEFINE_COUNTER , 和COUNTER_VALUE。Manual里有详细的用法。


    4.5 Verify
    QALoad没有提供一个通用的Assertion机制,像unit test framework里的assert机制在QALoad里没有提供。


    针对WWW,它提供了一个Verify函数,但只能处理page title的验证。


    Verify函数的调用结果根据 运行时 错误处理机制的不同有不同的行为。
    如果错误处理设置为 Continue,那么它返回一个False值,程序继续执行。如果错误处理设置为Restart,程序会跳到ESTART_TRANSACTION_BOTTOM()执行。


    4.6 Validate
    在QALoad Workbench里,你不能Debug你的scrīpt,有时候非常不方便。但是,Workbench也提供了另外一种方法能让你快速排错,那就是validate。


    Validate能让你在workbench里立即运行一个测试脚本,而无需创建一个session,然后在player里运行。DEBUG的时候写一些print语句,然后validate应该很管用。


    Validate命令在editor编辑文档的右键菜单里。

    5 配置Session
    在Conductor里配置Session。作为通用工具,Conductor提供了很多参数,但很多我们都无需关心。我们重点关注下面2点
    · 如果配置虚拟用户
    · 如何配置Transaction
    配置好的Session可以保存为文件,方便下次调用。Session的配置一共分5页


    5.1.1 Test Information
    配置基本信息

    5.1.2 scrīpt Assignment
    在这里配置Transaction
    · scrīpt:选择要运行的脚本
    · Type:协议类型
    · Transaction:每个VU要运行多少个Transaction
    · Debug Options:调试选项,一般不修改
    · Error Handling:错误处理,参加前面的错误处理介绍。根据测试要求选择一种
    · Sleep Factory%:睡眠因子。所有用DO_SLEEP(st)的st在执行时都要乘上睡眠因子。比如DO_SLEEP(100), Sleep Factory = 10, 那么在运行时实际睡眠时间时100X10% = 10 Seconds
    · Pacing: Transaction依次启动的间隔时间
    · Time Option:一般不修改
    · External Date:配置DataPool在此。如果在脚本里使用到了DataPool,一定要在这里配置,否则运行时会找不到DataPool。

    5.1.3 Machine Configuration
    其实就是配置Player


    5.1.4 Monitoring Options
    集成ServerVantage。ServerVantage部署在目标server上用来收集目标server的performance信息。现在没有用到。


    5.1.5 Machine Assignment
    在这里配置VU
    · scrīpt:运行的scrīpt
    · WWW:协议类型
    · Starting VU:启动的时候有多少VU
    · VU Increment:每次增加几个VU
    · Time Interval:增加VU的时间间隔
    · Ending VU:最多加多少VU
    · Machine:Player所在的Machine
    · Mode:Thread模式或者Process模式,在windows上一般选择thread,如果在linux/unix上,可以选择process 

    6 Analyze
    Analyze再次体现了商业工具的价值。从Analyze可以得到测试相关的各个方面的数据。

    6.1.1 报告的基本模式
    在查看令人眼花缭乱的各种report之前,我们需要了解这些报告的基本模式。


    Player收集数据的模式是 周期性的 对运行系统做快照。那么自然地,在report地时候,都是以运行时间为X坐标轴,数据值为Y坐标轴。

    6.1.2 具体的报告介绍
    理解了这一点,那么也就能理解所有的Report。比如在Report Panel里report:
    1) Summary
    基本的统计信息。主要是执行时间,Transaction失败数目,主要的Checkpoint的时间。
    2) Session
    Session里配置的信息
    3) Concurrent User
    整个执行时间段,VU数目的变化情况
    4) Response Time Analysis
    整个执行时间段,每种Transaction的响应时间变化情况
    5) Output
    错误信息输出
    6) Client Throughput
    整个执行时间段,client端的一些信息,比如接受到的数据,发送的数据,随时间变化的信息。
    7) Transaction Throughput
     整个执行时间段,Transaction个数随时间变化的信息
    8) Top Ten Longest Checkpoint Duration
    显示最耗时的Checkpoint,因为Checkpoint总是和特定的步骤相关,所以实际显示了最耗时的步骤。


    其他的3个panel,Checkpoints,Counters,Player Performance Counters,其数据展示都是以运行时间为X坐标轴,数据值为Y坐标轴这种形式。

  • 我的自行车被虐待了

    2007-06-08 17:28:43

    明天准备骑车回家。下午到车库去检查一下我的车车。

    到了车库往那个熟悉的角落望去,竟然没有。心里一惊,莫不是遭偷了?马上又安慰自己,车库里不会被偷的。
    到处看看,终于发现了,原来被拿到了外面的棚子里。虽然有个棚子,但雨水还是能飘进来。。。果然,链条都有部分生锈了。唉,郁闷。

    和守车的老太婆说不清。虽然我交的是助动车位的钱,但她看我的是自行车,就为我拿到外面去了。我告诉她不要把我得车放外面。她说不会有雨淋到的,又说车好多没有地方放。。。上海话我也不太懂,我干脆闭嘴了。

    我把车翻过来,竟然从后架上滴下一些水来。老太婆看见了,只好闭嘴了。我上上油,检查了一下胎压。

    期间过来一个老头,照例又问这个车多少钱,得知价钱后,又开始鄙视不买助动车买个自行车。还和老太婆热烈的讨论起来。

    检查好了。这个时候,不知道老太婆是不是良心发现,说可以停在屋内,并她给我找了一个位置。

    上海呆得太闷了。明天骑车回家,哈哈,又可以享受单车飞驰得乐趣了!



  • 解决web application的本地化问题

    2007-06-02 09:26:38

    一个java web application,开始只是支持英文,后来需要提供中文支持。前前后后搞了几天,终于全部解决。

    这个程序基于 servlet/jsp+spring+hibernate, 数据库是MySql。我把问题分解为下面的问题
        0) MySql支持中文
        1) 字符串资源支持多国语言
        2) 页面显示中文
        3) 提交中文form
        4) Ajax中包括中文

    为了问题简单,server端都使用unicode,用utf8编码,包括MySql。

    1 MySql支持中文

    在mysql.ini中
    default-character-set=utf8

    在spring的context定义中,作如下设置
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="url">
            <value><![CDATA[jdbc:mysql://localhost/echo?useUnicode=true&characterEncoding=UTF-8]]></value>
        </property>
    </bean>

    2 字符串资源支持多国语言


    字符串资源支持多国语言
    也就是根据浏览器的locale,页面元素显示为用户能懂的文字。这里需要用到资源文件。

    3 页面显示中文

    对于servlet,写一个filter,在里面设置response.setContentType("text/html; charset=UTF-8");
    对于jsp,在文件头加一行,<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

    4 提交中文form

    还是在上面的filter中,在从request里取得parameters之前,指定编码方式
    request.setCharacterEncoding("utf8");这样request.getParameter的适合,就会用utf8的解码方式。

    5 Ajax中包括中文

    我用的是buffalo,它已经解决好这个问题了。所有中文都会用utf8编码后提交。
  • Ruby+Watir经验谈: 包装Watir::IE

    2007-06-01 11:10:12

    如果我们要设计一个测试某个Web Server的框架,可以想象会经常在不同的页面跳转。在跳转的时候,你会希望只需提供url path而不是完整的url。但Watir::IE的goto方法需要全路径,所以一种方法是这样

        ie.goto("http://#{$serverip}:#{$serverport}/addUser"); # 用全局变量的方式

    但显然我们希望更好的调用方式是

        ie.goto("/addUser"); # 理想的调用方式

    二者的易用性差别不言而喻。但这就需要修改Watir::IE的行为,让他能接受url path的方式。在这里也体现了Ruby的强大之处,它的class定义是open的,你可以在任意一个地方修改它。


    module Watir
        # 修改Watir::IE就是这么简单
        class IE
        # 参数url定义了协议,地址,和端口
        # for example:
        #   * 10.10.10.10
        #   * 10.10.10.10:8080
        #   * http://10.10.10.10
        #   * https://10.10.10.10
        #
        # parameter 'attach' is a boolean, true means that if there is an existing IE browser,
        # don't launch a new one, jsut attach the ie object to it.
        #
        # @exception Watir::Exception::NoMatchingWindowFoundException if attaching failed
        def initialize(url, attach=false)
            Everbright::Basic.assert_true(!url.nil?, "occUrl shouldn't be nil")
            
            url = url.strip.upcase
            # "10.10.10.10" => [[nil, nil, "10.10.10.10"]]
            # "https://10.10.10.10" => [["https://", "https", "10.10.10.10"]]
            resultAry = url.scan( /^((https?):\/\/)?(.+)$/)
            @scheme, @occUrl = resultAry[0][0] || "http", resultAry[0][2]
            Everbright::Basic.assert_true(!@occUrl.nil?, "no site ip found from #{@occUrl}")

            if attach
            attach_init(:url, Regexp.compile(url))
            else
            create_browser_window
            set_defaults
            end
        end
            
        # 这个方法不应该被访问
            def IE.start( url = nil )
            raise Everbright::Basic::EverbrightException.new("The method shouldn't be called in Everbright framework")
            end

        # 这个方法不应该被访问
        def IE.attach(how, what)
            raise Everbright::Basic::EverbrightException.new("The method shouldn't be called in Everbright framework")
            end


        alias _goto goto

        # 我们需要重写goto方法
        #
            # URL is like: /gateway/login.jsp?user=.....
        # URL shouldn't be like: http://10.10.10.10/gateway/login.jsp.....
        def goto(path)
            return nil if path.nil?
            Everbright::Basic.assert_true(!(path =~ /^https?:\/\//), "URL should be like: /gateway/login....")
           
            log "goto: #{path}"
                _goto("#{@scheme}://#{@occUrl}#{path}")
            end

        end
    end

    这样,一个在其他语言里实现起来非常麻烦的功能,在ruby里只是a piece of cake.

    在c++里,需要实现一个wrapper,把Watir::IE的每个方法都重写一遍,虽然大多数都是简单的转发。在java里要容易点,如果在容器里流行的是AOP拦截,应该也可以使用DynamicProxy这个高级功能,但总之没有ruby来的优美漂亮。
1065/6<123456>
Open Toolbar