【腾讯TMQ】【浅谈Chromium中的设计模式(二)】——pre/post和Delegate模式_腾讯移动品质中心TMQ的博客-程序员秘密

技术标签: 测试分析  

Pre/post

请注意pre/post不能算是典型意义上的设计模式,Pre/post是契约式编程思想的概念。但是在从chromium代码中确实能看到不少他们的身影。

契约式编程中的PRE/POST

契约式编程(英语:Design by Contract,缩写为DBC)在Wiki上的解释:契约式编程是一种设计计算机软件的方法。这种方法要求软件设计者为软件组件定义正式的,精确的并且可验证的接口,这样,为传统的抽象数据类型又增加了先验条件、后验条件和不变式。这种方法的名字里用到的“契约”或者说“契约”是一种比喻,因为它和商业契约的情况有点类似。

在《程序员修炼之道:从小工到专家》中专门有一条讲的就是契约式编程(按合约设计)。

DesignbyContract的核心是断言(assertion)。所谓“断言”,是指永远为真的布尔型语句,如果不为真,则程序必然存在错误。通常情况下,检查断言的时机,应该局限于调试(debug)阶段,而不是代码的实际执行阶段。实际上,完成的程序永远不应期望断言会被检查。

DesignbyContract使用了三类断言:后继条件(post-conditions),前提条件(pre-conditions),以及不变量(invariants)。其中前驱条件与后继条件都是针对操作(operation)而言的。

前提条件preconditions:acondition that must hold up on invocation of a function在方法被调用之前就必须满足的条件。

后继条件post-conditions:acondition that must hold up on exit from a function法被调用之后所要保持的条件

不变量invariants:acondition that must always hold for objects of the class,except while a public member function is executing.在方法的执行过程中,不变量可能为假,但是,在其他任何对象能够与被调用方进行交互的时刻,不变量断言必须恢复为真。

在之前MBT的探索中,我们曾经尝试使用了PRE/POST模型,可参考文章http://tmq.qq.com/2016/11/pre_post_explore/

Chromium中的PRE/POST代码设计

虽然c++11不支持contract的语法,但是从chromium的代码上也可以看到代码也采用了pre/post的方式来设计。

我们可以从chromium的启动代码中看下pre/post思想是怎么使用的。

下图是Chromium中浏览器启动时候的代码顺序:

具体函数调用可以参考网上文章(http://blog.gclxry.com/chromium-framework-start/)。

启动的主要逻辑都是在Browser Main RunnerImpl,可以看到下面这段函数也是典型的pre/post的设计:

上面函数在main_loop_->Main Message Loop Start之前, 先调用main_loop_->Pre Main Message Loop Start准备相应的环境, 在执行完main_loop_->Main Message Loop Start之后又调用main_loop_->Post Main Message Loop Start来做后置条件的相关操作。

在每个layer里面都有对应的pre/post代码:

Browser MainLoop 里面的Pre Main Message LoopStart 又会调用对应的平台的Chrome应用(_parts对应的就是Chrome Browser Main Parts,不同的平台的应用不一样,windows上面就是Chrome Browser Main Parts Win)的Pre Main Message Loop Start。

在Chrome Browser Main Parts里面Pre Main Message Loop Start又会调用chrome_extra_parts_(多个扩展应用Chrome Browser Main Extra Parts:其中Chrome Browser Main Parts是对应的平台,
Chrome Browser Main Extra Parts是对应不同的Chrome toolkits (e.g., GTK, VIEWS, ASH, AURA, etc.))的Pre Main Message Loop Start。

PRE/POST设计的好处

在编程语言不支持了DBC的情况下,在代码层面采用PRE/POST的设计可以极大地提高代码的易读性和可维护性。且建立这种契约明确了我们什么时候什么阶段该干什么事。

Delegate模式

Delegate模式介绍

维基百科的解释:委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。委托模式是一项基本技巧,许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式。委托模式使得我们可以用聚合来替代继承,它还使我们可以模拟mixin。

Delegate在chromium中的使用

Chromium是一个复杂的开源项目,其中应用了丰富的设计模式来组织代码,应用最广泛的应该算是Delegate Pattern(委托模式)。

在chromium中,每个模块具体功能的实现基本上都是通过Delegate类来实现的,如果开发者继承该Delegate类,并加以实现就能很方便的完成定制,倘若开发者不需要某个模块的功能,也就不用实现相关的Delegate类,那么该模块就不会发挥效用。

Delegate的使用使得自动化测试也非常容易,这些测试需要能直接检测Chromium中的某个特性或功能能不能正常工作,检查新添加的代码对原有的代码有没有影响,但是由于有些功能需要手动干预才能正常工作,比如下载模块中弹出的对话框需要手动选择保存文件的地址和文件名;这些会给自动测试代码带来麻烦,但是有了delegate的设计,我们在测试代码中可以直接实现对应的Test的delegate,继承正常工作的delegate,该类做一些简单的修改事先填好一些数据,从而绕开需要手动输入代码块的执行。这就一方面完成了对已有代码的测试,也同时兼具了自动化。

Chromium中Delegate模式的例子

在Chromium项目中有个Download Manager类(content里面),它负责完成任务的下载功能,当在浏览器中点击某个不能被渲染的链接时,浏览器就认为该链接的文件需要下载,就通过Download Manager来完成下载流程。

当在浏览器中点击某个不能被渲染的链接时,浏览器就认为该链接的文件需要下载,就通过Download Manager来完成下载流程。但是下载文件的实际工作都是在Download Manager Delegate中完成的,比如选择文件的路径,检查文件路径名是否合法,下载时候完成之类等。开发者只需要自己设计一个新的Delegate类来继承Download Manager Delegate,并覆盖相应的方法即可完成下载功能,另外需要通过Set Delegate方法,在程序开始时把自定义类的对象注册到Download Manager中。目前Chrome,Content Shell,CEF3和Crosswalk都有自己的实现。

Chrome基于Download Manager Delegate的UML类图:

下面看看自动化测试中应该怎么使用设置test的delegate:

首先,基于Chrome Download Manager Delegate实现自己的测试的delegate:Delaying Download Manager Delegate。

上面代码就是基于Chrome Download Manager Delegate定义了测试所需要的Delaying Download Manager Delegate类,并重写了方法Should Complete Download 这样就可以绕开真实的delegate里面复杂的Should Complete Download逻辑判断,并简单的返回了false来进行测试。

在对应的测试用例代码里面调用set Delegate替换为测试的delegate。


定义完了测试的delegate类,调用SetDelegate来使得Delaying Download Manager Delegate生效。

**未完待续……

版权所属,禁止转载

扫描下方二维码,关注微信公众号:腾讯移动品质中心TMQ,获取更多测试干货!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/TMQ1225/article/details/79882152

智能推荐

双系统Ubuntu18.04安装_「已注销」的博客-程序员秘密

一、下载镜像下载地址:Ubuntu18.04二、准前准备1)在当前系统下压缩出空闲分区windows系统:此电脑 - > 右击 -> 管理 -> 新窗口的磁盘管理 ,选择空闲空间足够的磁盘压缩,压缩后可以看到未分配空间。2)启动盘制作Ubuntu18的启动盘制作十分方便,win10直接打开下载的iso镜像,拷贝所有内容至U盘3)BIOS设置以我的联想拯救者...

计算机为什么要使用补码计算?_为什么计算机使用补码存储和计算_冰夫子的博客-程序员秘密

今天无意中翻看大学的笔记,看到一个问题:通用计算机为什么使用二进制补码做数学运算?毕业这么多年了,被这个问题给折腾了一下,估计工作N年的人猛地你问他这个问题,他一定会回答没有什么原因,因为用补码,所以用补码;偏偏我不是那样的人,简单的问题能解释明白,也不容易;一下是总结:--------------------------------------------------------------...

keil里Flash Download failed - “Cortex-M4“等一系列配置问题_flash download failed corte-m4_all_but的博客-程序员秘密

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入欢迎使用Markdown编辑器你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Mar

hdu-3292-佩尔方程+矩阵快速幂_迭代方程 矩阵快速幂_alusang的博客-程序员秘密

这个题理解完了可以提取出x^2-n*d^2=1这个式子,一看就是典型的佩尔方程,然后求解第k项就行了。要注意n是完全平方数的时候无解。求最小特解用的暴力#include <iostream>#include <cstring>#include <cstdio>#include <cmath>#include <vector...

为什么国外程序员爱用 Mac?_为什么代码用mac__yshuai的博客-程序员秘密

Mac 在国外很受欢迎,尤其是在 设计/web开发/IT 人员圈子里。普通用户喜欢 Mac 可以理解,毕竟 Mac 设计美观,简单好用,没有病毒。那么为什么专业人士也对 Mac 情有独钟呢?从个人使用经验来看我想有下面几个原因:1、Mac OS X 是基于 Unix 的。这一点太重要了,尤其是对开发人员,至少对于我来说很重要,这意味着Unix 下一堆好用的工具都可以随手捡到。如果你是个 win

随便推点

IE-LAB网络实验室:什么是WAN?定义了广域网,示例以及它们的发展方向_ielab悦然的博客-程序员秘密

WAN可以远距离连接较小的网络,其架构,协议和技术已经发展到最新的版本SD-WAN。istock如果它不适用于广域网,则无法为地理位置偏远,远程办公或在线进行任何组织的组织创建统一网络。但是,WAN确实存在并且已经存在了数十年,随着需求的增加和技术变得更加强大,不断发展以便更快地承载越来越多的流量。什么是WAN?WAN是一种使用各种链路的网络 - 专线,多协议标签交换(MPLS),虚拟专...

@Override是什么意思?[email protected]_S巴尔扎克的博客-程序员秘密

@Override是Java5的元数据,自动加上去的一个标志,告诉你说下面这个方法是从父类/接口 继承过来的,需要你重写一次,这样就可以方便你阅读,也不怕会忘记 @Override是伪代码,表示重写(当然不写也可以),不过写上有如下好处:1>可以当注释用,方便阅读 2>编译器可以给你验证@Override下面的方法名是否是你父类中所有的,如果没有则报错比如你如果

文件名排序_文件名先后字符排序_mimepp的博客-程序员秘密

在各个不同的系统中,对文件名的排序有着不同的实现,这里做个记录。

idea terminal控制台配置git bash及中文乱码问题_superXX07的博客-程序员秘密

1.修改控制台shell路径:setting -> Tools -> Terminal -> Shell path,修改为git安装路径。修改完毕,在控制台输入exit断开session连接,然后重新打开即可。2.中文乱码问题在idea安装目录下找到idea.exe.vmoptions和idea64.exe.vmoptions文件,在文件的最后添加: ...

js函数传递参数的方式------传值与传递指针_aigm9302的博客-程序员秘密

原则:1. 基本类型:传值2. 对象:传递指针应用场景之一:用jq选择器获取某个div后(例如:element),准备进行某些修改,之后添加到页面中去。采取例一的方式,append后发现修改的内容没有改变。采用例二的方式,成功修改。举例一:传值1、调用:....setId(element);***.append(element);.......