watin----- web单元测试利器

1.谁来阅读本文
使用watin做web页面的单元测试的开发人员,由于该工具使用已经小项目组内部培训,故重点在于总结和分析实际使用中的问题以及资料的收集,而不是入门教程   :)
 
2. 官方网站
 
3.附件内容解释\\ 忽略我吧  呵呵
 a.UnitTest.rar   为单元测试的示例解决方案
 ConsoleApplication为控制台程序版本
 WebApplication为web页面版本
 POUnitTests为公安网办项目实际测试用例的部分示例代码,里面附有部分watin代码的使用说明,下面的主题会一一概述
 
  b.watin相关软件及文档.rar
_WatinRecorder Setup Lite为自动记录工具,比较弱智,改进中
NUnit-2.4.0-r2-net-2.0为基于.net2.0的测试工具
HtmlElement_Mappings.xls为watin和页面控件的映射关系
IEDevToolBarSetup.msi为微软的ie开发帮助工作栏
WatiN-1.0.0.4000-net-2.0.zip为包含源码的watin
 
So have a fun~
让我们的思想改变世界 “)
 
--------------------------------------------------
常见问题的分析和解决方案
 
0.如何构建web单元测试
 
 本质上为3步:
  找到控件;触发事件;断言判断
 
如何覆盖功能点?
在已有的功能模块下,自己按照测试的用例手册来细分功能点,每一个功能点用region块划分,各自实现自己的操作和验证
譬如:先把region的功能点覆盖到,注释好,再写实现过程和验证代码
 
  [Test]
        public void CreateCaseInfo()
        {
            #region 新建案件基本信息
          
            #region 1.错误信息提示
            //行政案件
            //直接保存
            Assert.IsTrue(ie.Html.Contains("请输入案件名称!"));
            Thread.Sleep(1000);
            #endregion
 
            #region 2.时间控件验证
            //1.填写必要信息,填错报案和发案时间
            Assert.IsTrue(ie.Html.Contains("发案开始时间不能晚于报案时间"));
 
            //2.填错发案时间
            //发案开始时间迟于结束时间
            Assert.IsTrue(ie.Html.Contains("发案结束时间不能晚于发案开始时间!"));
 
            //3.填错发案时间
            //发案结束时间迟于报案时间
            Assert.IsTrue(ie.Html.Contains("发案结束时间不能晚于当前时间!"));
            #endregion
 
            #region 3.取消保存
            //正确发案结束时间
            //保存按钮
 
            //弹出类似案件检查页面
            Assert.IsFalse(ie.Html.Contains("保存成功!"));
            #endregion
           
            #region 4.成功保存
             //保存按钮
             Assert.IsTrue(ie.Html.Contains("保存成功!"));  Assert.AreEqual("2007-03-29",ie.TextField("ctl00_MainContentPlaceHolder_FoldingPanel2_case_EditCtrl_caseInfo_EditCtrl_HappenTime_End_DTP_txtDate").Text);
            Assert.AreEqual("陈永春", ie.TextField("ctl00_MainContentPlaceHolder_FoldingPanel2_case_EditCtrl_caseInfo_EditCtrl_HandleUserList_TB").Text);
            #endregion
 
            //给下一个测试方法预留反应时间
            Thread.Sleep(1000);
       
            #endregion
        }
 
---------------------------------
 
1.ie.waitforcomplete 和 thread.sleep 的使用
 
上述的两个方法,用来等待ie的加载
watin的专门的waitforcomple通过侦探ie的busy和ready状态来判断,实际使用时候有自己的局限性
 
一般而言可以用ie.waitforcomplete来代替sleep,后来发现如果有类似AJAX postbacks之类的请求时,不是ie的状态能指出的,也即是ie.waitforcomplete失效,此时加上assert断言,页面加载并没有完成,必须手动来sleep足够的时间
譬如 Atlas UpdatePanel 控件,就必须sleep
 
当然,还有一个解决办法,就是在ajax之类的postback后,页面肯定存在或肯定不存在的控件的值或状态,譬如
 
- 1.look for an element that will exist after the "AJAX postback":
 
         ie.Element(findBy).WaitUntilExists();
 
- 2. wait until an element does not exist anymore
 
         ie.Element(findBy).WaitUntilRemoved();
- 3.  wait until an element has a certain (known) value that indicates the "AJAX postback" has finished:
 
         ie.Element(Find.ById("...") && Find.ByCustom("atributename","knownvalue").WaitUntilExists();
 
即将发布的1.1版本的解决方法:
 
         ie.Element(Find.ById("...")).WaitUntil(Find.ByCustom("atributename","known value");
 
---------------------------
 
2    如果发现watin不支持的html标签时
例如 nobr ,可以自定义一个属性  new Attribute()
注意system也有这个System.Attribute,所以要加上全部的限定符
         
ElementCollection nobrElements = ie.Elements.Filter(new
WatiN.Core.Attribute("tagname", new
StringEqualsAndCaseInsensitiveComparer("nobr")));
//从控制台检查是否找到了对应的值          
 for(int i=0;i
                Console.WriteLine(nobrElements[i].InnerHtml);
 
---------------------------------- 
 
3.    事件的精确控制
 
譬如当新开页面关闭自己并刷新父页面时候,新开的页面的“保存并关闭”按钮的前台事件可以简单的通过调用
 
similarSuspectIE.Button("ctl00_MainContentPlaceHolder_Save").FireEventNoWait("onclick");
 
FireEventNoWait会只触发指定元素的指定事件并忽略waitForComplete(该返回值在弹出窗口的处理上,没有考虑很周全),在面临开了2个以上新窗口,并依次关闭且刷新父页面的情况下,会让测试走过去 --!以往的测试策略无法走通
这个是公安网办 新建嫌疑人-->编辑 -->类似嫌疑人对比 ,然后关闭类似嫌疑人页面,自动关闭当前页面并依次刷新父页面碰到的问题
 
----------------------------------
4.    confirm等modeless弹出窗口以及弹出的ie窗口的定位
confirm窗口:
 //注册Confirm窗口处理方法
            ConfirmDialogHandler deleteConfirm = new ConfirmDialogHandler();
            ie.AddDialogHandler(deleteConfirm);
            //删除按钮,弹出Confirm对话框
            //出现Model类型对话框时候,如Confirm、Alert等,父窗口的按钮点击事件必须为ClickNoWait()
            ie.Button("ctl00_MainContentPlaceHolder_FoldingPanel2_Delete_Button2").ClickNoWait();
            //确认删除
            deleteConfirm.WaitUntilExists();
            deleteConfirm.OKButton.Click();
            //有忽略弹出的Confirm引起的ie返回状态代码和平时不一致的作用
            ie.WaitForComplete();
 
弹出新ie窗口的定位:
 IE newIE= IE.InternetExplorers()[IE.InternetExplorers().Length - 1];
发布于 由 haoliu0 篇评论 票数 良好 [4 out of 5]。

基本原则zz~

 (下面这些文字不是我的原创,是我偶尔在网上发现的)

记录下来,大家一起分享,现在面对的是太多的信息,却无法找到自己最想要的 sigh~

  作者:金蝶中间件公司CTO袁红岗

  不知不觉做软件已经做了十年,有成功的喜悦,也有失败的痛苦,但总不敢称自己是高手,因为和我心目中真正的高手们比起来,还差的太远。世界上并没有成为高手的捷径,但一些基本原则是可以遵循的。

  1. 扎实的基础。数据结构、离散数学、编译原理,这些是所有计算机科学的基础,如果不掌握他们,很难写出高水平的程序。据我的观察,学计算机专业的人比学其他专业的人更能写出高质量的软件。程序人人都会写,但当你发现写到一定程度很难再提高的时候,就应该想想是不是要回过头来学学这些最基本的理论。不要一开始就去学OOP,即使你再精通OOP,遇到一些基本算法的时候可能也会束手无策。

  2. 丰富的想象力。不要拘泥于固定的思维方式,遇到问题的时候要多想几种解决问题的方案,试试别人从没想过的方法。丰富的想象力是建立在丰富的知识的基础上,除计算机以外,多涉猎其他的学科,比如天文、物理、数学等等。另外,多看科幻电影也是一个很好的途径。

  3. 最简单的是最好的。这也许是所有科学都遵循的一条准则,如此复杂的质能互换原理在爱因斯坦眼里不过是一个简单得不能再简单的公式:E=mc2。简单的方法更容易被人理解,更容易实现,也更容易维护。遇到问题时要优先考虑最简单的方案,只有简单方案不能满足要求时再考虑复杂的方案。

  4. 不钻牛角尖。当你遇到障碍的时候,不妨暂时远离电脑,看看窗外的风景,听听轻音乐,和朋友聊聊天。当我遇到难题的时候会去玩游戏,而且是那种极暴力的打斗类游戏,当负责游戏的那部分大脑细胞极度亢奋的时候,负责编程的那部分大脑细胞就得到了充分的休息。当重新开始工作的时候,我会发现那些难题现在竟然可以迎刃而解。

  5. 对答案的渴求。人类自然科学的发展史就是一个渴求得到答案的过程,即使只能知道答案的一小部分也值得我们去付出。只要你坚定信念,一定要找到问题的答案,你才会付出精力去探索,即使最后没有得到答案,在过程中你也会学到很多东西。

  6. 多与别人交流。三人行必有我师,也许在一次和别人不经意的谈话中,就可以迸出灵感的火花。多上上网,看看别人对同一问题的看法,会给你很大的启发。

  7. 良好的编程风格。注意养成良好的习惯,代码的缩进编排,变量的命名规则要始终保持一致。大家都知道如何排除代码中错误,却往往忽视了对注释的排错。注释是程序的一个重要组成部分,它可以使你的代码更容易理解,而如果代码已经清楚地表达了你的思想,就不必再加注释了,如果注释和代码不一致,那就更加糟糕。

  8. 韧性和毅力。这也许是"高手"和一般程序员最大的区别。A good programming is 99 weat and 1 afflatus。高手们并不是天才,他们是在无数个日日夜夜中磨练出来的。成功能给我们带来无比的喜悦,但过程却是无比的枯燥乏味。你不妨做个测试,找个10000以内的素数表,把它们全都抄下来,然后再检查三遍,如果能够不间断地完成这一工作,你就可以满足这一条

----这个8th条,就罢了,太花时间证明了 赫赫

期待自己的代码大全2的到来~~~

发布于 由 haoliu0 篇评论

面向对象 面向抽象?

今天看代码,查资料无意中逛到了一个牛人的blog,发现了关于一些设计思想的想法,很有启发,虽然没有全部理解,但是也更正了我的某些面向对象的想法,Share之,转载一部分有体会的  以后慢慢感受~

1.面向对象的核心意义并不在于你把东西封装成什么样了,不在于有什么东西被继承出来了,最重要的是他容许我们用抽象的方式来构建一个软件。比如当我们写代码写到:

stream.Write(buff, 4, buff.Length - 4);
或者
hashbuff = hasher.ComputeHash(buff);

我们是否需要关心stream到底是什么,hasher用的又是什么算法呢?如果我们由始至终,在做相应的东西的操作都用相同的stream对象和hasher对象,任务是否都应当能够正确完成呢?应该是能够正确完成的,因为这正是我们的期待。如果让我们来设计某一个stream,是否应该从这个角度去考虑如何设计这一个类呢?如果我们定义这个stream变量,是否应该更抽象一点呢?考虑这么一个函数:
void DoSomething(FileStream stream, MD5CryptoServiceProvider hasher, byte[] buff) {...}

如果写成如下形式将会更加灵活,也更加符合面向对象(面向抽象)的真实含义:
void DoSomething(Stream stream, HashAlgorithm hasher, byte[] buff) {...} 

2.面向对象的核心是面向抽象,但我们看到,实际发展的过程并非如此。我们在过去有着太多错误的概念了,比如说这个面向对象技术的面向对象,就太容易让我们认为,这项技术的核心就是面向对象。于是很多时候我们写一个“面向对象”的程序充斥的过度的对象,泛滥的继承,以及不知道为什么的封装。并且不少开发者,包括我在内,都曾经认为所谓的面向对象就是把一些要素抽象成对象,进行封装,然后从某个基类派生出万物。好比有一个基类叫做物体,派生出活物与死物,活物派生出细菌病毒植物动物,动物里面有猴鸡狗猪和人,人里面有张三李四王二麻子(还有个娃)。
没错,面向对象当然得包括这些,但是这不是全部,更不是根本。根本就是在于我们写某些东西的时候,不需要关心具体的对象是什么,只需要知道至少它应该是一个什么。比如上一节当中的例子,DoSomething只需要知道stream是一个流,而hasher是一个哈希算法提供者就够了。至于具体提供的是什么样的流和哈希算法,则不应当是我们关心的,而是使用我们这段代码的用户所关心的。如此一来,我们就可以在设计这一段我们所关心的功能的时候,不需要考虑过多的、过于具体的、不断变化的问题。
仔细想想,我们是否真的已经明白了面向对象的核心所在呢?

3.protected是一个授权问题,而非保密问题

protected:表明该成员容许在派生类当中被使用,但不允许使用本类对象的用户代码直接使用。实际上是对设计人员的有限度授权,和对用户的拒绝授权。

面向对象的封装并非保护你的秘密,而是防止被错误使用,是为了明确划分问题的界限。就“保护”这个词而言,更进一步的讲,它并非对使用该对象的用户(下面称为用户)做出使用某个成员的授权,而是对延展该类的设计人员(下面称为设计人员)做出延展问题领域的授权。

4.抽象到了头是什么?当然不是什么都没有,不是虚空太极。抽象的本质是描述某个主语能够完成一组什么动作,这些动作构成了什么样的功能。如果我们从这样的一个角度去想,就会发现接口能够很好的完成这样的任务。比如说IList,它表达的是“一个列表”这样的抽象,这个抽象能够提供一组相应的动作,比如"object this[int index];" 能够取出或设置列表当中的第n项内容。只有拥有IList接口所定义的成员,才能够表明这个物体确实能够称之为“一个列表”。“服务”这个词也许能够更加深刻的表达上述的含义:
class ArrayList : IList {...}
这样的定义表明,ArrayList提供“列表”相关的服务。如果我们在定义变量和参数的时候更多的使用接口,而不是具体的类,那么我们的代码将拥有更大的自由度。这个时候我们关心的事某个对象是否能够提供我所需要的服务,而不关心他到底是什么。

在面向对象刚刚开始的时候,我们在这个方面走进了一个误区,就是用多继承来解决上面的这个需求。比如我们可以在C++里面看到Stream派生自IStream和OStream,这么做也能够解决问题,也许同样能够表达“服务”这个含义。但是我觉得这样做还是会引起许多不必要的麻烦,比如同名称冲突等。现代的理论甚至直接告诉我们继承他不是一个好东西,如果能够用引用来代替继承,那就不要继承,如DesignPattern里面的Decorate等。

不知道没有清晰的思想定位,怎么去写出优秀的代码~  sigh 路漫漫其修远兮,吾将上下而求索

边看书边代码,天天都有新的认识

发布于 由 haoliu0 篇评论 票数 良好 [4 out of 5]。

三省而后知~

成功誓言
------北仑外国语学校学生每日必读

我有幸进入外语学校,成为这个大家庭的一员,我要做一个优秀家庭的一员。我生活在处处充满成功而又激烈竞争的时代。我来到这个世上,肩负着光荣的使命,我决心为建设家乡,报效祖国而勤奋学习。

我相信:天生我材必有用。在这个世界上我是独一无二的,我无条件的喜欢自己;我充分的高度地相信自己;我也相信自己的父母,同学和尊敬的老师,他们是我成才的巨大助力。

我相信:榜样是力量,我尊敬毛泽东,周恩来,邓小平,爱因斯坦等伟大人物,我决心以他们的伟大思想和品格来激励和鞭策自己,作为我学习和仿效的榜样。

我相信:全力以赴追求,一定能够实现我的人生目标。每当生活中学习上遇到困难时,我将在战略上藐视一切困难,在战术上重视一切困难;,每当我在前进中遇到挫折和失意时,我不会忘记,伟大总是经过煎熬的;每当我意志消沉,信心下降时,我会时刻提醒自己:世界是进步的,前途是光明的,并把自己头脑中一切软弱无能的念头统统赶跑。

我相信:学习是事业的基础。我不被淘汰的唯一条件就是学习。我牢记:“少壮不努力,老大徒伤悲。”我要学会做人,学会学习,学会健体,学会思考,学会审美,以适应高速发展的社会,而这一切恰恰是孝父母,敬师长,报祖国的最好表现。

我相信:“人最大的敌人是自己。”因此我要努力使“坚强的我”战胜“软弱的我”,“勤奋的我”战胜“懒惰的我”,“利他的我”战胜“自私的我”。

我相信:成功一定属于自强不息,积极进取的我。

真不错~

发布于 由 haoliu0 篇评论

准备开搞了

一个人没有物理设计没有概念设计,做出一个能看能用的东西,满ft的个~

以后谁个没有物理设计概念设计,我就自己做设计,所以哈 ,要努力要学习。在一个项目中成长是很快的,白天干活,晚上就回去看看书,整理下思路,豁然间很多的东西就有所顿悟

爱生活,爱编程事业~

发布于 由 haoliu0 篇评论