搜狗浏览器2.0版本实现了Webkit和Trident双内核引擎,当访问兼容性好的站点时,浏览器会使用Webkit内核进行渲染解析;当访问兼容性较差的站点时,浏览器会使用Trident内核进行渲染解析。浏览器通过双核选择流程判断采用何种内核:
1.当访问一个Url时,浏览器将Url按照一定的规则转换为Pattern;
2.将Pattern与黑白名单进行匹配。
3.如果匹配白名单,则使用Webkit内核;
4.如果命中白名单的同时又命中黑名单,则使用Trident内核;
5.如果没有命中白名单,则使用Trident内核。
浏览器双核选择流程决定了用户浏览页面的体验好坏,因此双核选择流程的功能正确性和稳定性具有举足轻重的作用。为了能够提高测试效率,以及用尽可能多的Url提升功能覆盖度,双核选择流程需要自动化辅助测试。
双核选择流程中,Url转换为Pattern模块、Pattern匹配黑白名单模块是双核选择流程中的两个核心算法,其中存在了大量的字符串操作,功能逻辑性强,输入容易构造,输出容易检验。因此在评估可行性后决定采用集成测试的方式,对双核选择模块的Url2Pattern()函数和MultiCoreChooser()函数进行自动化的集成测试。
我们采用了经典的VS2005 + TCL搭建集成测试环境。这个测试环境的优点是:
搭建步骤:
创建DriverFunc.h文件:
//驱动函数的声明:
//
//TclEx_Dochoose是浏览器双核选择的函数
int TclEx_DoChoose( ClientData clientData, Tcl_Interp * interp, int argc , char* argv[]);
int TclEx_Url2Pattern( ClientData clientData, Tcl_Interp * interp, int argc , char* argv[]);
创建DriverFunc.cpp文件
#include "stdafx.h"
#include "DriverFunc.h"
#include "MultiCoreChooser.h"
#include "ListCenter.h"
//1.5版本双核选择函数DoChoose
int TclEx_DoChoose( ClientData clientData, Tcl_Interp * interp, int argc , char* argv[])
{
……
CString strUrl;
//string strUrl;
int iExpectResult = ParamInitValue;
int iResult = 0;
//参数:获取期望结果
if ( TCL_OK != Tcl_GetInt(interp , argv[1] , &iExpectResult ) )
{
interp->result = "para1 error";
return TCL_OK;
}
…
//参数:获取Url
char szUrl[2048] = { 0 };
strncpy( szUrl, argv[2] , 2048 );
DWORD dwNum = MultiByteToWideChar( CP_ACP , 0 , szUrl , -1 ,NULL , 0 );
wchar_t * pwszUrl;
pwszUrl = new wchar_t[dwNum];
if ( !pwszUrl )
{
delete []pwszUrl;
}
MultiByteToWideChar( CP_ACP , 0 , szUrl , -1 , pwszUrl , dwNum );
//传入的szUrl必须转为Unicode
iResult = MultiCore::ChooseCore( pwszUrl ); //调用待测试函数
delete []pwszUrl;
if ( iResult != iExpectResult )
{
interp->result = "Test Failed!";
}
else
{
interp->result = "Test Succeded!";
}
return TCL_OK;
}
int TclEx_Url2Pattern( ClientData clientData, Tcl_Interp * interp, int argc , char* argv[] )
{
……
int iExpectResult = ParamInitValue;
int iResult = 0;
//参数:获取期望结果
if ( TCL_OK != Tcl_GetInt(interp , argv[1] , &iExpectResult ) )
{
interp->result = "para1 error";
return TCL_OK;
}
……
//参数:获取Url
char szUrl[2048] = { 0 };
strncpy( szUrl, argv[2] , 2048 );
char szPattern[2048] = { 0 };
ListCenter::Url2Pattern( szUrl , szPattern ); //调用待测试函数
//输出执行结果
//fix bug:如果使用strcpy_s的话会出现崩溃,所以使用strcpy。
int ilen = strlen( szPattern );
if ( TCL_RESULT_SIZE > ilen )
{
strcpy( interp->result, szPattern );
}
else
{
interp->result = "result is too long";
}
return TCL_OK;
}
6.编写Tcl运行环境的Main函数并注册外部命令。
#include "stdafx.h"
#include "Main.h"
#include
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// The one and only application object
CWinApp theApp;
using namespace std;
Tcl_Interp * MyInterp;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
……
//创建TCL解释器
MyInterp = Tcl_CreateInterp();
//初始化解释器
Tcl_Init( MyInterp );
//创建外部命令
Tcl_CreateCommand( MyInterp , "DoChoose" , TclEx_DoChoose, NULL , NULL );
Tcl_CreateCommand( MyInterp , "Url2Pattern" , TclEx_Url2Pattern , NULL, NULL );
Tcl_CreateCommand( MyInterp , "GetPath" , TclEx_GetPath, NULL , NULL );
……
while(1)
{
_tprintf( _T("Please input the TclScript Name:\n") );
scanf( "%s" , &szScriptName );//这里用scanf_s会出错,所以还是原用scanf
sprintf_s( sScript, "%s\\%s", szScriptPath ,szScriptName);
try
{
rCode = Tcl_EvalFile( MyInterp , (char * ) sScript );
}
catch (CException* e)
{
// Note: DELETE_EXCEPTION(e) not required
LPTSTR pszErrText;
e->GetErrorMessage(pszErrText,100);
AfxMessageBox(pszErrText,MB_OK);
//DELETE_EXCEPTION(e);
}
if ( TCL_OK != rCode )
{
_tprintf( _T("There are errors in your Tcl File\n") );
}
}
return nRetCode;
}
1.编写Tcl脚本并调用扩展命令。
Url2Pattern.tcl
#Log开关
set bFlagLog 1
#获取当前程序路径
set source "WHITE.src"
set dest "WHITE.dst"
set curpath [ GetPath ]
#用例文件
set testdatafile [format "%s/%s" $curpath $source]
#结果文件
set testresultfile [format "%s/%s" $curpath $dest]
#打开文件
set hftestdata [open $testdatafile r]
set hftestresult [open $testresultfile w]
…
#不断的逐行地读取用例数据文件直到文件结束
while { ![eof $hftestdata] } {
#获取一行数据并把它保存到变量sstr中
gets $hftestdata sstr
……
#执行DoChoose,结果写入ret($i)
set ret($i) [DoChoose $p3($i) $p4($i)] #调用已注册的TCL命令,将测试数据和预期结果传入MultiChooseCore函数。
#Log:输出执行结果到屏幕
if { 1 == $bFlagLog } {
puts $ret($i)
}
…
puts $hftestresult "---------------------------------------------------------"
#关闭文件
close $hftestdata
close $hftestresult
2.准备测试用例。
第一列是用例执行标志位,Y代表执行,N代表不执行。
第二列为用例编号。
第三列是预期结果,0代表Trident内核,1代表Webkit内核。
3.测试结果: