-----使用技术手段解决问题,坚信注重每一个细节,把熟悉的做到一种极致,一定会有创新出现。-----

ruby+watir--watir3.0上实现快照/截图

我想在watir框架运行时,在出现错误“FAIL”状态前建立一个快照,就想到了watir的截图功能,在网上找了一些例子(参考:http://www.cnblogs.com/sky_online/archive/2009/12/13/1546252.html),但是不好使,提示“Win32API”的错误。

环境:Ruby192+watir3.0.0

gem list信息如下:

gem list
Microsoft Windows XP [版本 5.1.2600]
(C) 版权所有 1985-2001 Microsoft Corp.
C:\Documents and Settings\Administrator>gem list
*** LOCAL GEMS ***
addressable (2.2.8)
builder (3.0.0)
childprocess (0.3.2)
commonwatir (3.0.0)
cucumber (1.2.1)
diff-lcs (1.1.3)
ffi (1.0.11)
gherkin (2.11.1)
hoe (3.0.6)
json (1.7.3)
libwebsocket (0.1.3)
mini_magick (3.2.1)
minitest (1.6.0)
multi_json (1.3.4)
nokogiri (1.5.3 x86-mingw32)
rake (0.8.7)
rautomation (0.7.2)
rdoc (2.5.8)
rubygems-update (1.8.24)
rubyzip (0.9.8)
s4t-utils (1.0.4)
selenium-webdriver (2.25.0, 2.21.2)
subexec (0.0.4)
user-choices (1.1.6.1)
watir (3.0.0)
watir-classic (3.0.0)
watir-webdriver (0.6.1)
watir-webdriver-performance (0.1.3.1)
win32-api (1.4.8)
win32-process (0.6.5)
windows-api (0.4.1)
windows-pr (1.2.1)
xml-simple (1.1.1)
C:\Documents and Settings\Administrator>

这个LibScreen.rb的例子适合在watir1.6.5版本的,有高手试验过。直接运行LibScreen.rb例子的话,会出现的错误,请过森破的深入分析,需要把脚本中的vkKeyScan.Call()中带问号的修改一下就可以,如下:所有带问号?的都要修改一遍,否则。。

vkKeyScan.Call(?V)
替换成
vkKeyScan.Call("V".getbyte(0))

?V输出的是ASCII 86(在低版本中),那在我的高版本中显示的是V,这就是高版本和低版本的区别。

经过验证,本地保存快照成功。并对LibScreen.rb的例子进行了功能扩展:可以保存.jpg、.bmp、.png、.gif格式的文件;有人说图片比较占用磁盘空间,在脚本中把另存为默认成PNG格式的文件(虽然和保存的格式对不上),因为占用空间小,针对这个我还专门做了对比:

LibScreen.rb
class ScreenClass
def initialize
require "Win32API"
end
#功能说明:
#- 将文件重命名
#
 #参数说明:
#- from:原文件路径,必须带文件名,格式如:c:\\test.txt
#- to:新文件路径及名称,必须带文件名,格式如:c:\\test_bak.txt,不带该参数时,默认在原文件名后加上日期
#
 #调用示例: 
#- $TxtClass.RenameFile("c:\\test.txt","c:\\test_bak.txt")
#- $TxtClass.RenameFile("c:\\test.txt")
#
 #返回值说明:
#- 成功:返回true
#- 失败:返回false
def RenameFile(from,to = nil)
begin
if (FileTest::exist?(from)) and (File.basename(from) =~ /.*\..*/ )
if (to == nil)
extname = File.extname(from)
filename = File.basename(from,extname)
new_filename = filename + '.' + Time.now.strftime("%Y%m%d%H%M%S") + extname
to = File.dirname(from) + '/'+ new_filename
end
File.rename(from, to)
return true
else
puts "重命名文件失败,原因:文件不存在,路径为#{from}"
return false
end
rescue StandardError => bang
puts "Error running script: " + bang
return false
end
end
#功能说明:
#- 获取文件的真实路径
#
 #参数说明:
#- file_path:原文件路径,如果原文件路径不存在,系统自动创建相应路径
#- return_file:是否返回路径中的文件名,默认未返回
#
 #调用示例: 
#- $TxtClass.GetRealPath("#{File.dirname(__FILE__)}/http://www.cnblogs.com/input/data.xls" )
#
 #返回值说明:
#- 成功:返回真实的路径
#- 失败:返回false
def GetRealPath(file_path,return_file = 'Y')
begin
@@file_name = ''
@@real_dir_row = []
if (file_path.include?("\\"))
file_path = file_path.to_s.gsub('\\','/')
end
if (file_path.include?("/"))
file_basename = File.basename(file_path) #获取文件名
file_dirname = File.dirname(file_path)
if (file_basename =~ /.*\..*/)
file_dirname = File.dirname(file_path)
else
file_basename = ''
file_dirname = file_path
end
if (!FileTest::exist?(file_dirname)) #判断目录是否存在,不存在则创建相应目录
 FileUtils.makedirs(file_dirname)
end
if (file_dirname[0,2] == './')
real_dir = Pathname.new(File.dirname(File.dirname(file_dirname[0,2]))).realpath
real_path = File.join(real_dir,file_dirname[2,file_dirname.length] )
else
real_path = file_dirname
end
if (real_path.include?(".."))
temp_row = real_path.split('/')
temp_row.each do |dir|
if(dir == "..")
@@real_dir_row.pop
else
@@real_dir_row.push(dir)
end
end
real_path = @@real_dir_row.join('/')
end
if (return_file.upcase == 'Y')
result = File.join(real_path,file_basename)
else
result = real_path
end
result = result.to_s.gsub('/','\\')
return result
else
puts "获取文件路径失败,原因:#{real_path}路径格式不正确。"
return false
end
rescue StandardError => bang
puts "Error running script: " + bang
return false
end
end #def GetRealPath
def ScreenCapture(file_path , active_window_only=false, save_as_bmp=false)
keybd_event = Win32API.new("user32", "keybd_event", ['I','I','L','L'], 'V')
vkKeyScan = Win32API.new("user32", "VkKeyScan", ['I'], 'I')
winExec = Win32API.new("kernel32", "WinExec", ['P','L'], 'L')
openClipboard = Win32API.new("user32", "OpenClipboard", ['L'], 'I')
setClipboardData = Win32API.new("user32", "SetClipboardData", ['I', 'I'], 'I')
closeClipboard = Win32API.new("user32", "CloseClipboard", [], 'I')
globalAlloc = Win32API.new("kernel32", "GlobalAlloc", ['I', 'I'], 'I')
globalLock = Win32API.new("kernel32", "GlobalLock", ['I'], 'I')
globalUnlock = Win32API.new("kernel32", "GlobalUnlock", ['I'], 'I')
memcpy = Win32API.new("msvcrt", "memcpy", ['I', 'P', 'I'], 'I')
file_basename = File.basename(file_path) #获取文件名
if(file_basename.upcase =~ /.*.(JPG|BMP|PNG|GIF)/)
real_file_path = GetRealPath(file_path) #获取文件的真实路径
if (FileTest::exist?(real_file_path))
RenameFile(real_file_path)
end
if active_window_only ==false
keybd_event.Call(0x2C,0,0,0) # Print Screen
else
keybd_event.Call(0x2C,1,0,0) # Alt+Print Screen
 end
winExec.Call('mspaint.exe', 5)
sleep(1)
# Ctrl + V : Paste
keybd_event.Call(0x11, 1, 0, 0)
keybd_event.Call(vkKeyScan.Call("V".getbyte(0)), 1, 0, 0)
keybd_event.Call(vkKeyScan.Call("V".getbyte(0)), 1, 0X2, 0)
keybd_event.Call(0x11, 1, 0X2, 0)
# Alt F + A : Save As
keybd_event.Call(0x12, 1, 0, 0)
keybd_event.Call(vkKeyScan.Call("F".getbyte(0)), 1, 0, 0)
keybd_event.Call(vkKeyScan.Call("F".getbyte(0)), 1, 0X2, 0)
keybd_event.Call(0x12, 1, 0X2, 0)
keybd_event.Call(vkKeyScan.Call("A".getbyte(0)), 1, 0, 0)
keybd_event.Call(vkKeyScan.Call("A".getbyte(0)), 1, 0X2, 0)
sleep(1)
# copy filename to clipboard 复制
hmem = globalAlloc.Call(0X0002, real_file_path.length+1)
mem = globalLock.Call(hmem)
memcpy.Call(mem, real_file_path, real_file_path.length+1)
globalUnlock.Call(hmem)
openClipboard.Call(0)
setClipboardData.Call(1, hmem)
closeClipboard.Call
sleep(1)
# Ctrl + V : Paste粘贴
keybd_event.Call(0x11, 1, 0, 0)
keybd_event.Call(vkKeyScan.Call("V".getbyte(0)), 1, 0, 0)
keybd_event.Call(vkKeyScan.Call("V".getbyte(0)), 1, 0X2, 0)
keybd_event.Call(0x11, 1, 0X2, 0)
#快照另存为
if save_as_bmp == false
# goto the combo box
keybd_event.Call(0x09, 1, 0, 0)
keybd_event.Call(0x09, 1, 0X2, 0)
sleep(0.5)
# select the first entry with J 选择另存为的类型,这里以png格式为例,如果另存为gif格式在保存时会提示“失真的信息”
keybd_event.Call(vkKeyScan.Call("P".getbyte(0)), 1, 0, 0)
keybd_event.Call(vkKeyScan.Call("P".getbyte(0)), 1, 0X2, 0)
sleep(0.5)
end
# Enter key
keybd_event.Call(0x0D, 1, 0, 0)
keybd_event.Call(0x0D, 1, 0X2, 0)
sleep(1)
# Alt + F4 : Exit
keybd_event.Call(0x12, 1, 0, 0)
keybd_event.Call(0x73, 1, 0, 0)
keybd_event.Call(0x73, 1, 0X2, 0)
keybd_event.Call(0x12, 1, 0X2, 0)
sleep(1)
puts "快照保存的路径为:#{real_file_path}"
return true
else
puts "保存的文件扩展名不正确,路径必须带文件名且文件扩展名必须为.jpg、.bmp、.png、.gif"
return false
end
end # def ScreenCapture end
end #class ScreenClass end

验证:

require "watir"
require "LibScreen.rb"
def test
ie = Watir::IE.new
ie.goto("http://www.baidu.com")
#初始对象
i = ScreenClass.new
#截取整个屏幕
#i.ScreenCapture("c:\\test1.png")
#截取当前激活的窗口
i.ScreenCapture("c:\\test1.png",true,false)
end

 

另外watir还有自带的截图工具,路径Ruby\lib\ruby\gems\1.9.1\gems\watir-classic-3.0.0\lib\watir-classic\screen_capture.rb,一样还是需要把所有带问号?的都要修改一遍。这个自带的我们可以直接引用:

require 'watir-classic/screen_capture'
include Watir::ScreenCapture
def test
ie = Watir::IE.new
ie.goto("http://www.baidu.com")
screen_capture("c:\\123111.jpg",true,false)
end

算啦 我把自带的screen_capture.rb代码沾上来吧,我已经修改过啦,可以参考:

screen_capture.rb
require 'Win32API'
module Watir
module ScreenCapture
KEYEVENTF_KEYUP = 0x2
SW_HIDE = 0
SW_SHOW = 5
SW_SHOWNORMAL = 1
VK_CONTROL = 0x11
VK_F4 = 0x73
VK_MENU = 0x12
VK_RETURN = 0x0D
VK_SHIFT = 0x10
VK_SNAPSHOT = 0x2C
VK_TAB = 0x09
GMEM_MOVEABLE = 0x0002
CF_TEXT = 1
# this method saves the current window or whole screen as either a bitmap or a jpeg
# It uses paint to save the file, so will barf if a duplicate filename is selected, or the path doesnt exist etc
# * filename - string - the name of the file to save. If its not fully qualified the current directory is used
# * active_window - boolean - if true, the whole screen is captured, if false, just the active window is captured
# * save_as_bmp - boolean - if true saves the file as a bitmap, saves it as a jpeg otherwise
def screen_capture(filename , active_window_only=false, save_as_bmp=false)
keybd_event = Win32API.new("user32", "keybd_event", ['I','I','L','L'], 'V')
vkKeyScan = Win32API.new("user32", "VkKeyScan", ['I'], 'I')
winExec = Win32API.new("kernel32", "WinExec", ['P','L'], 'L')
openClipboard = Win32API.new('user32', 'OpenClipboard', ['L'], 'I')
setClipboardData = Win32API.new('user32', 'SetClipboardData', ['I', 'I'], 'I')
closeClipboard = Win32API.new('user32', 'CloseClipboard', [], 'I')
globalAlloc = Win32API.new('kernel32', 'GlobalAlloc', ['I', 'I'], 'I')
globalLock = Win32API.new('kernel32', 'GlobalLock', ['I'], 'I')
globalUnlock = Win32API.new('kernel32', 'GlobalUnlock', ['I'], 'I')
memcpy = Win32API.new('msvcrt', 'memcpy', ['I', 'P', 'I'], 'I')
filename = Dir.getwd.tr('/','\\') + '\\' + filename unless filename.index('\\')
if active_window_only ==false
keybd_event.Call(VK_SNAPSHOT,0,0,0) # Print Screen
else
keybd_event.Call(VK_SNAPSHOT,1,0,0) # Alt+Print Screen
 end
winExec.Call('mspaint.exe', SW_SHOW)
sleep(1)
# Ctrl + V : Paste
keybd_event.Call(VK_CONTROL, 1, 0, 0)
keybd_event.Call(vkKeyScan.Call("V".getbyte(0)), 1, 0, 0)
keybd_event.Call(vkKeyScan.Call("V".getbyte(0)), 1, KEYEVENTF_KEYUP, 0)
keybd_event.Call(VK_CONTROL, 1, KEYEVENTF_KEYUP, 0)
# Alt F + A : Save As
keybd_event.Call(VK_MENU, 1, 0, 0)
keybd_event.Call(vkKeyScan.Call("F".getbyte(0)), 1, 0, 0)
keybd_event.Call(vkKeyScan.Call("F".getbyte(0)), 1, KEYEVENTF_KEYUP, 0)
keybd_event.Call(VK_MENU, 1, KEYEVENTF_KEYUP, 0)
keybd_event.Call(vkKeyScan.Call("A".getbyte(0)), 1, 0, 0)
keybd_event.Call(vkKeyScan.Call("A".getbyte(0)), 1, KEYEVENTF_KEYUP, 0)
sleep(1)
# copy filename to clipboard
hmem = globalAlloc.Call(GMEM_MOVEABLE, filename.length+1)
mem = globalLock.Call(hmem)
memcpy.Call(mem, filename, filename.length+1)
globalUnlock.Call(hmem)
openClipboard.Call(0)
setClipboardData.Call(CF_TEXT, hmem)
closeClipboard.Call
sleep(1)
# Ctrl + V : Paste
keybd_event.Call(VK_CONTROL, 1, 0, 0)
keybd_event.Call(vkKeyScan.Call("V".getbyte(0)), 1, 0, 0)
keybd_event.Call(vkKeyScan.Call("V".getbyte(0)), 1, KEYEVENTF_KEYUP, 0)
keybd_event.Call(VK_CONTROL, 1, KEYEVENTF_KEYUP, 0)
if save_as_bmp == false
# goto the combo box
keybd_event.Call(VK_TAB, 1, 0, 0)
keybd_event.Call(VK_TAB, 1, KEYEVENTF_KEYUP, 0)
sleep(0.5)
# select the first entry with J
keybd_event.Call(vkKeyScan.Call("J".getbyte(0)), 1, 0, 0)
keybd_event.Call(vkKeyScan.Call("J".getbyte(0)), 1, KEYEVENTF_KEYUP, 0)
sleep(0.5)
end
# Enter key
keybd_event.Call(VK_RETURN, 1, 0, 0)
keybd_event.Call(VK_RETURN, 1, KEYEVENTF_KEYUP, 0)
sleep(1)
# Alt + F4 : Exit
keybd_event.Call(VK_MENU, 1, 0, 0)
keybd_event.Call(VK_F4, 1, 0, 0)
keybd_event.Call(VK_F4, 1, KEYEVENTF_KEYUP, 0)
keybd_event.Call(VK_MENU, 1, KEYEVENTF_KEYUP, 0)
sleep(1)
end
end
end

 

posted @ 2012-12-04 17:52  ZhuQue  阅读(2456)  评论(0编辑  收藏  举报
多年性能测试、测试管理经验,专注银行、支付、电商行业,倾向于性能、安全、 监控、调优、模型、管理等方向的研究。
使用技术手段解决问题,坚信注重每一个细节,把熟悉的做到一种极致,一定会有创新出现。