目前,我在做测试自动化的项目,要用到smartbits,bps,testcenter和mu测试仪。通过调用测试仪提供的TCL API操作测试仪,从而实现测试用例的具体流程。我们用测试仪测试TOE时,会发现测试仪上会显示测试进度(1%,2%...)。以Bps为例,当执行到set objectName [$testObjectName run
-progress "bps::textprogress stdout"]命令时,就会在屏幕上同步输出当前的测试进度。为了与其他模块方便通信,我利用c++调用TCL脚本来实现用例。为了将tcl输出的测试进度获取并传递给其他模块,我利用windows API CreateProcess(),在c++与TCL脚本之间开辟了一条管道。下面是我的.tcl源码和c++源码,希望对从事这方面开发的同仁有益。
【.tcl】
set dir [file dirname [info script]]
lappend auto_path $dir
wm withdraw .
proc testProc {ip uname pwd} {
puts "loading bps package..."
package require bps
puts "bps package loading complete."
set var [bps::connect $ip $uname $pwd]
set test1 [$var createTest]
set comName [$test1 createComponent bitblaster bb41 1 2]
puts "test running.."
set fid [open "testProgress.txt" w+]
if [catch {open "testProgress.txt" w+} $fid] {
puts stderr "cann't open "testProgress.txt" w+: $fid"
} else {
set reObj [$test1 run -progress "bps::textprogress stdout"]
puts $fid $reObj
close $fid
}
puts "quit"
}
#------------------------------------------------------------------
# Analyze cmd options
#set proc_list [ info commands ]
#for { set i 0 } { $i < $::argc } { incr i } {
# if { -1 != [ lsearch -exact $proc_list [ lindex $::argv $i ] ] } {
# puts "Try to execute proc '[ lindex $::argv $i ]' ......"
# eval [ lindex $::argv $i ]
# }
#}
#-----------------------------------------------------------------
# Analyze cmd options
set proc_list [ info commands ]
for { set i 0 } { $i < $::argc } { incr i } {
set proc_name [ lindex $::argv $i ]
if { [ expr [ regexp -- {^-} $proc_name ] && \
-1 != [ lsearch -exact $proc_list [ string range $proc_name 1 end ] ] ] } {
set param_list ""
for { set j [ expr $i+1 ] } { $j < $::argc } { incr j } {
set param_name [ lindex $::argv $j ]
if { ![ regexp -- {^-} $param_name ] } {
lappend param_list $param_name
} else {
set i [ expr $j - 1 ]
break
}
}
puts "Try to execute proc '[ string range $proc_name 1 end ]' with params '$param_list' ......"
set eval_code [ list [ string range $proc_name 1 end ] ]
foreach param $param_list { lappend eval_code $param }
eval $eval_code
}
}
【注】:如果testProc不需要参数,则可以将两条“————”之间的代码解注释,将“----”下面的代码注释掉即可。
【c++】
#include "stdafx.h"
#include <Windows.h>
#include <string>
#include <process.h>
#include <iostream>
#include <stdio.h>
#include "tcl.h"
#include "tclDecls.h"
#pragma comment(lib,"tcl85.lib")
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
SECURITY_ATTRIBUTES sa;
HANDLE hRead,hWrite;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
if (!CreatePipe(&hRead,&hWrite,&sa,0)) {
cout<<"Error On CreatePipe()"<<endl;
return 0;
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
si.cb = sizeof(STARTUPINFO);
GetStartupInfo(&si);
si.hStdError = hWrite;
si.hStdOutput = hWrite;
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
string str1 = "D:\\Tcl\\bin\\wish85.exe test.tcl";
string str2 = "-";
string str3 = "test";
string str4 = "10.10.0.1";
string str6 = " ";
string str7 = "mobei";
string str8 = "mobei";
string str = str1+str6+str2+str3+str6+str4+str6 + str7 + str6 + str8;
char* strC = const_cast<char*>(str.c_str());
if (!CreateProcess(NULL,strC, NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi))
{
cout<<"Error on CreateProcess()"<<endl;
return 0;
}
CloseHandle(hWrite);
char buffer[4096] = {0};
DWORD bytesRead;
while (true)
{
if (ReadFile(hRead,buffer,4095,&bytesRead,NULL) == NULL)
{
cout<<"test"<<endl;
break;
}
else
{
string bufStr;
bufStr = buffer;
if (bufStr.find("quit") != -1)
{
break;
}
else
{
sendInfo(bufStr);//将测试进度发送给其他模块
cout<<"content of buffer is: "<<buffer<<endl;
}
}
}
cout<<"hello world"<<endl;
return 0;
}
由于ReadFile()是个阻塞函数,所以在tcl脚本里面输出一个字符,当在bufStr中找到这个字符时就退出循环,这里我输出的是quit,作为退出循环标志。测试的结果,我分别保存在了两个.txt文件中,可以通过分析文件获取,下面是用c++读取.txt文件的代码。
【readTxt】
// readTxt.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "iostream"
#include <fstream >
#include <string>
using namespace std;
string readTxt(string fileName);
int main(int argc, char* argv[])
{
string result = readTxt("passorfailed.txt");
cout<<"result is: "<<result<<endl;
if (result == "passed")
{
cout<<"test ok"<<endl;
}
else
cout<<"test failed"<<endl;
return 0;
}
string readTxt(string fileName)
{
ifstream infile;
char* fileNamePtr = const_cast<char*>(fileName.c_str());
infile.open (fileNamePtr);
if(!infile)
cout<<"error"<<endl; //判断文件是被成功打开
string num; //定义文件中的数据类型
char p; //定义一个字符读取文件中的空格和/或回车符
int M=1; //这里首先定义为1是因为最后一行的结束符是EOF,所以用'\n'来判断行的话, //最后一行会漏悼。所以先把它定义为1,也就相当于加上了最后一行!
int N=0;
while(!infile.eof()) //每次读入之前都要判断是否到了文件末
{
do{
infile.get (p);
if(p=='\n')
{
M++; //统计行数;
N=0; //一个新行开始时,列数置为0
cout<<endl; //一行之后输出一个换行符
}
}while(isspace((int)p) && !infile.eof ());//结束条件是读入的是空格或已到达文件末
N++; //统计列数
infile.putback (p); // 如果前面读入的不是空格或回车符,则要把刚才读入的字符返回到文件流中!
infile>>num; // 读入一个数
cout<<num<<" "; // 输出刚才读入的数据
}
infile.close (); // 关闭文件
return num;
}
如果从事过这方面开发的同仁有更好的解决方案,欢迎不吝赐教。