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

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

require 'watir-webdriver' $browser = Watir::Browser.new(:firefox, :profile => "botmode") => # 

它可以使用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问题,请道歉。 我只是不确定如何表达它并继续获得不相关的搜索结果。

我想,你不能记住另一个过程中的变量。 但解决方案可能是创建一个主进程并在线程循环中处理脚本,定期检查浏览器的运行状态。 我在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浏览器是否与进程列表一起运行

这很棘手但可能适合你

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

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

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

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

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

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

ruby脚本退出后,它产生的进程(可能根本不属于同一个PID树,如firefox-bin)有一个可预测的“会话负责人”,结果是调用rubyprogram.rb的bash shell的父节点 。在我的情况下。 在Bash中以$ PPID的forms提供,因为当你必须高于$$时

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

 #!/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 

可选由于我在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 

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

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

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

(更多关于如何在内部使用TCPServer序列化对象? )

同时,即使尝试使用Marshal(也是内置于Ruby但以二进制格式存储)进行序列化,会导致一个非常合理的错误,即无法转储TCPServer对象(显然包含在我的Watir中:浏览器指向通过$浏览器)

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

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