watir浏览器对象可以在以后的Ruby进程中重用吗?

时间:2011-12-25 23:21:25

标签: ruby serialization object watir watir-webdriver

所以,让我们说经常运行一个脚本来打开浏览器并做网络事情:

require 'watir-webdriver'

$browser = Watir::Browser.new(:firefox, :profile => "botmode")
 => #<Watir::Browser:0x7fc97b06f558 url="about:blank" title="about:blank"> 

它可以使用browser.close优雅地结束,或者它可能会更快崩溃并留下需要大量内存的Firefox进程,直到它们累积并使服务器慢速爬行时才会被忽视。

我的问题有两个:

  • 什么是好的做法,以确保即使在脚本失败的任何地方导致立即错误退出,子进程将始终被清理(我已经有很多短的begin-rescue-end块用于其他无关的小测试)
  • 更重要的是,我可以简单地记住这个Watir :: Browser:0x7fc97b06f558对象地址或PID,并在一个全新的Ruby进程中将其重新分配给另一个$ browser变量,例如irb?即webdriver上的孤立浏览器可以在同一台机器上使用watir-webdriver在其他程序中重新附加吗?从irb我可以进入并重新连接到崩溃的Ruby脚本留下的浏览器,检查它所在的网站,检查出错的地方,哪些元素与预期不同等等。

后者的另一个非常有利的用途是避免每天可能有数百个浏览器启动和关闭的开销......最好将一个活着作为一个守护进程。第一次运行将尝试使用我专门准备的 botmode 配置文件重用以前的浏览器对象,否则创建一个。然后我故意不在我的脚本末尾调用$ browser.close。如果没有其他的东西,我会在工作中杀死Xvfb:99显示FF在一天结束时运行到底(让FF别无选择,只能死了,如果还在运行的话)。是的我知道Selenium独立jar,但也试图避免那个java服务足迹。

如果这是一个基本的Ruby问题,请道歉。我只是不确定如何表达它并继续获得不相关的搜索结果。

5 个答案:

答案 0 :(得分:2)

我想,你不能记住另一个进程中的变量。但解决方案可能是创建一个主进程并在线程循环中处理脚本,定期检查浏览器的运行状态。我在Cucumber + watir的验收测试中使用了类似的东西。所以它会是这样的:

require 'rubygems'
require 'firewatir' # or watir
@browser = FireWatir::Firefox.new

t = Thread.new do
    @browser.goto "http://google.com"
    #call more browser actions here
end
while not_exit?
  if t.stop?
      # error occurred in thread, restart or exit
  end
  if browser_live?
      # browser was killed for a some reason
      # restart or exit
  end
end
@browser.close

not_exit? - 可以通过TRAP获得ctrl + C

browser_live? - 您可以检查firefox浏览器是否与进程列表一起运行

这很棘手但可能适合你

答案 1 :(得分:1)

我很确定在ruby退出的时候,任何像浏览器对象这样的句柄或指针都会变得无效。因此,在后来的ruby过程中重新使用某些东西可能不是一个好方法。另外我可能错了,但似乎webdriver不是很擅长连接到正在运行的浏览器进程。因此,对于你的工作方法,它真的需要被一些调用所有测试等的主进程包裹起来。嘿等等一秒,这听起来像一个框架,你可能已经(或者可能应该是) )首先使用。

因此,更好的解决方案可能是查看您用于运行测试的任何框架,并研究在每次测试之前和之后运行的“设置/拆除”操作(可以使用不同名称)的任何功能,测试组或所有测试。这样做很好,因为大多数框架都允许您运行任何单个测试或一组您想要的测试。如果你的测试设计得很好,它们可以单独运行,而不必指望系统通过先前的测试保持在某种完美的状态。因此,这些设置/拆卸动作也被设计为以这种方式工作。

作为示例,Cucumber在功能级别具有此功能,其概念是“背景”,其基本上旨在通过定义在功能文件中的每个方案之前运行的常用步骤来干燥方案。 (例如导航到并登录到您的站点)这可能包括调用一系列步骤,以查看是否存在浏览器对象,如果没有,则创建一个。但是你需要将它放在每个特征文件中,这些文件开始变得非常干燥。

幸运的是,黄瓜还允许通过Hooks在一个地方实现这一目标。您可以定义在步骤之前运行的钩子,在特定条件下,每个场景之前“之前”和“之后”,以及在任何场景之前运行一次的代码,以及定义为运行'at_exit'的代码,您可以在其中关闭所有方案运行后的浏览器。

如果我使用黄瓜,我会看一下env.rb中的一些代码的想法,这些代码将在开始时运行以创建浏览器,并通过at_exit代码来关闭浏览器。然后也许还可以在before钩子中进行编码,该钩子可以检查浏览器是否仍在那里并在需要时重新创建它,并且可能在after钩子中注销操作。保留诸如登录各个场景之类的内容,或者如果功能中的所有场景都使用相同类型的用户登录,则保留background块。

答案 2 :(得分:1)

您可以像这样使用DRb
浏览器池:

require 'drb'
require 'watir'

browser = Watir::Browser.new :chrome
DRb.start_service 'druby://127.0.0.1:9395', browser

gets

,然后在测试脚本中使用此浏览器:

require 'drb'
browser = DRbObject.new_with_uri 'druby://127.0.0.1:9395'
browser.goto 'stackoverflow.com'

答案 3 :(得分:0)

不是一个解决方案,而是使用pkill解决我的问题的第一部分。在这里张贴,因为它比我希望的要少得多。

ruby​​脚本退出后,它产生的进程(可能根本不属于同一个PID树,如firefox-bin)有一个可预测的“会话负责人”,结果是父进程。在Bash中以 $ PPID 的形式提供,因为当您必须高于 $$ 时。

因此,要真正清理不需要的重量级过程,例如。红宝石坠毁后:

#!/bin/bash
# This is the script that wraps on top of Ruby scripts

./ruby_program_using_watirwebdriver_browser.rb  myparams &  # spawn ruby in background but keep going below:

sleep 11 # give Ruby a chance to launch its web browser

pstree -panu $$  # prints out a process tree starting under Bash, the parent of Ruby. Firefox may not show!

wait  # now wait for Ruby to exit or crash

pkill -s $PPID firefox-bin  # should only kill firefox-bin's caused above, not elsewhere on the system

# Another way without pkill, will also print out what's getting killed if anything:
awk '$7=="firefox-bin" && $3=="'$PPID'" {print $1}' <(ps x -o pid,pgid,sess,ppid,tty,time,comm) | xargs -rt kill

OPTIONAL 由于我在DISPLAY:99上使用专用的Xvfb Xwindows服务器进行网络驱动,我也可以依靠xkill:

timeout 1s  xwininfo -display :99 -root -all |awk '/("Navigator" "Firefox")/ {print $1}' |xargs -rt  xkill -display :99 -id  
# the timeout is in case xkill decides to wait for user action, when window id was missing

答案 4 :(得分:0)

只是我的问题第2部分的更新。

似乎有一个CAN使用YAML序列化Watir:Browser对象,因为它是基于文本的内容对我来说非常有趣(例如我曾梦想过调整隐藏在私有类私有元素中的一些东西......但这是一个单独的主题)

从YAML反序列化仍然很麻烦。虽然我没有测试超过第一次尝试它给我一些reg exp解析错误...不知道那是什么。

(更多内容见how to serialize an object using TCPServer inside?

同时,甚至试图与元帅,这也是内置在Ruby,但存储二进制格式进行序列化,导致有关无法转储TCPSERVER对象(显然包含我的Watir内一个非常合理的冠冕堂皇的错误:浏览器指向浏览器)

总而言之,我对这些结果并不感到惊讶,但仍然非常有信心有一种方法,直到Watir到达更原生的东西(如PersistentWebdriver或者过去的时候是如何在jssh时代你可以简单地附加到一个已正在运行的浏览器,其中包含正确的扩展名)

在此之前,如果对工作对象进行序列化+反序列化变得非常棘手,我将使用我的Ruby的一部分进行守护,以保持对象的持久性并节省频繁且昂贵的设置/拆卸。我确实对一些已建立的(单元测试)框架有所了解,但似乎在我的整体软件结构中还没有完全适合 - 毕竟我不是网络测试。