本次
测试中碰到的问题是这样的,在消息的传送过程中遇到了 DEC 加密的过程, LoadRunner 录制到的全是加密的消息,比如我录制了某一个用户的登陆,发送消息,退出,但由于是加密的,只能单个用户使用,但如果我想并发多少个用户就存在很多问题,最直接的一个问题就是用户名是加密的,密码是加密的,当然你可以说让程序那里注掉加密的代码进行明码的测试,当然也是一种办法。但程序组提出了要使用更真实的方法来模拟,这时就必需使用下面介绍的方法。
一开始是直接把 API 移植到 LoadRunner 中来,不过由于加密算法异常复杂,有几层循环,而角本是解释执行的,进行一次加密运算可能需要好几分钟,当然在角本里可以把角本本身运行的时间去掉,但这样做显然没有直接调用 DLL 来的效率高。由于程序组比较忙,所以无法提供 DLL 给测试,所以测试完成了 DLL 的编写,并在 LoadRunner 中调用成功,高效的完成了用户信息加密,参数关联,成功的完成了测试。
动态链接库的编写
在 Visual C++6.0 开发环境下,打开 FileNewProject 选项,可以选择 Win32 Dyna mic - Lin k Library 建立一个空的 DLL 工程。
1 . Win32 Dyna mic - Lin k Library 方式创建 Non-MFC DLL 动态链接库
每一个 DLL 必须有一个入口点,这就象我们用 C 编写的应用程序一样,必须有一个 WINMAIN 函数一样。在 Non-MFC DLL 中 DllMain 是一个缺省的入口函数,你不需要编写自己的 DLL 入口函数,用这个缺省的入口函数就能使动态链接库被调用时得到正确的初始化。如果应用程序的 DLL 需要分配额外的内存或资源时,或者说需要对每个进程或线程初始化和清除操作时,需要在相应的 DLL 工程的 .CPP 文件中对 DllMain() 函数按照下面的格式书写。
BOOL APIENTRY DllMain(HANDLE hModule, DW ORD ul_reason_for_call,LPVOID lpReserved)
{
switch( ul_reason_for_call
{
case DLL_P ROC ESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_P ROC ESS_DETACH:
break;
default:
break;
}
return TRUE;
}
参数中, hMoudle 是动态库被调用时所传递来的一个指向自己的句柄 ( 实际上,它是指向 _DGROUP 段的一个选择符 ; ul_reason_for_call 是一个说明动态库被调原因的标志,当进程或线程装入或卸载动态链接库的时候,
操作系统调用入口函数,并说明动态链接库被调用的原因,它所有的可能值为: DLL_P ROC ESS_ATTACH: 进程被调用、 DLL_THREAD_ATTACH: 线程被调用、 DLL_P ROC ESS_DETACH: 进程被停止、 DLL_THREAD_DETACH: 线程被停止; lpReserved 为保留参数。到此为止, DLL 的入口函数已经写了,剩下部分的实现也不难,你可以在 DLL 工程中加入你所想要输出的函数或变量了。
我们已经知道 DLL 是包含若干个函数的库文件,应用程序使用 DLL 中的函数之前,应该先导出这些函数,以便供给应用程序使用。要导出这些函数有两种方法,一是在定义函数时使用导出关键字 _dec ls pec(dllexport) ,另外一种方法是在创建 DLL 文件时使用模块定义文件 .Def 。需要读者注意的是在使用第一种方法的时候,不能使用 DEF 文件。下面通过两个例子来说明如何使用这两种方法创建 DLL 文件。
1 )使用导出函数关键字 _dec ls pec(dllexport) 创建 MyDll.dll ,该动态链接库中有两个函数,分别用来实现得到两个数的最大和最小数。在 MyDll.h 和 MyDLL.cpp 文件中分别输入如下原代码:
//MyDLL.h
extern "C" _dec ls pec(dllexport) int desinit(int mode);
extern "C" _dec ls pec(dllexport) void desdone(void);
extern "C" _dec ls pec(dllexport) void des_setkey(char *subkey, char *key);
extern "C" _dec ls pec(dllexport) void endes(char *blo ck , char *subkey);
extern "C" _dec ls pec(dllexport) void dedes(char *blo ck , char *subkey);
//MyDll.cpp
#include"MyDll.h"
// 这里我用了比较大小的函数代替了我要实现的函数
int desinit(int a, int b)
{
if(a>=b)return a;
e ls e
return b;
}
int desdone(int a, int b)
{
if(a>=b)return b;
e ls e
return a;
}
该动态链接库编译成功后,打开 MyDll 工程中的 debug 目录,可以看到 MyDll.dll 、 MyDll.lib 两个文件。 LIB 文件中包含 DLL 文件名和 DLL 文件中的函数名等,该 LIB 文件只是对应该 DLL 文件的 " 映像文件 " ,与 DLL 文件中, LIB 文件的长度要小的多,在进行隐式链接 DLL 时要用到它。读者可能已经注意到在 MyDll.h 中有关键字 "extern C" ,它可以使
其他编程语言访问你编写的 DLL 中的函数。
LoadRunner 调用动态链接库
上面完成动态链接库开发后,下面就介绍动态链接库如何被 LoadRunner 进行调用,其实也是很简单的。在 LoadRunner 中的 DLL 调用有局部调用与全局调用,下面介绍局部调用。
首先把你编译的 DLL 放在角本路径下面,这里是 MyDll.dll,MyDll.lib. 然后在 Action 中使用
lr_load_dll("MYDll.dll" ,此函数可以把 DLL 加载进来,让你调用 DLL 里面的函数,而 DLL 中的运算是编译级的,所以效率极高,代码样例如下:
#include "lrs.h"
Action()
{
//
int nRet = 6;
char sr ck ey[129];
memset(sr ck ey, 'a', 128);
lr_message(lr_eval_st ring (sr ck ey));
lr_load_dll("MyDLL.dll" ;
nRet = desinit(5,8);
lr_message(" 比较的结果为 %d",nRet);
return 0;
}
运行结果
比较的结果为 8
全局的动态链接库的调用则需要修改 mdrv.dat ,路径在 LoadRunner 的安装目录下面( LoadRunner/dat directory );在里面修改如例:
[WinSock ]
ExtP rio rityType=protocol
WINNT_EXT_LIBS=wsrun32.dll
WIN95_EXT_LIBS=wsrun32.dll
LIN UX_EXT_LIBS=liblrs.so
SOLARIS_EXT_LIBS=liblrs.so
HPUX_EXT_LIBS=liblrs.sl
AIX_EXT_LIBS=liblrs.so
LibCfgFunc=winso ck _exten_conf
UtilityExt=lrun_api
ExtMessageQueue=0
Ex tCm d Lin eOverwrite=-WinInet No
Ex tCm d Lin eCo nc=-UsingWinInet No
WINNT_DL LS =user_dll1.dll, user_dll2.dll, ...
// 最后一行是加载你需要的 DLL
这样你就可以在 LR 中随意的调用程序员写的 API 函数,进行一些复杂的数据加密,准备的一些操作,进行复杂的测试。同时如果你觉的有大量高复杂的运算也可以放在 DLL 中进行封装,以提高效率。