在rspec执行的每个poltergeist测试中,如果我使用:
创建一个新会话 Capybara.session_name="some_session_name"
phantomjs实例作为子进程启动,并且在测试结束之前永远不会退出,从而导致构建服务器上出现OOM。
我认为这是由于未能调用driver.quit,如readme of Poltergeist中所述:
如果您手动运行几个水豚会话,请确保在不再需要会话时调用session.driver.quit。忘记这一点会导致内存泄漏,系统的资源可能会比您预期的更早耗尽。
但是,我在测试的page.driver.quit
块中调用了after
。
下面是我的后块代码。 $adhoc_sessions
是我每次设置Capybara.session_name
时填充的全局变量,其值与Capybara.session_name
上设置的值相匹配。
config.after(:each) do
if example.metadata[:js]
$adhoc_sessions.each do |session_name|
Capybara.using_session( session_name ) do
page.driver.quit
end
end
$adhoc_sessions.clear
end
有关我在这里可以做得更好的建议吗?我没有打电话给一些清理命令吗?
答案 0 :(得分:1)
我找到了一个来自两个约束的解决方案:
重新创建TOO MANY OPEN FILES错误的方法错误 - 请勿使用此颜色!!
# you have to do quite a few test runs to cause the open files error
config.append_after(:each) do
session_pool = Capybara.instance_variable_get("@session_pool")
session_pool.each do | key, value |
value.driver.quit
end
session_pool.clear
end
我认为这是一个真正的恶作剧者,但我不在乎......这就是为什么......在运行上面的代码时,我注意到创建一个恶作剧会话是一个明显缓慢且资源密集的操作。所以,我认为我宁愿拥有一个永远不会消失的会议池......就像Capybara的设计方式一样。
这种方法的唯一问题就是像我一样使用Capybara.session_name,这是在每个测试的基础上提出任意测试名称。也许在一个测试中,我希望每个session_name与用户的数据库ID相同。或者也许我想出了我在测试中使用的5个常数,以及5个不同的常量用于不同的测试。换句话说,我可以在我的测试套件中使用100s的session_name,但是对于任何给定测试的人来说,我最多只有一些会话。所以一个好的解决方案重用了poltergeist会话,但是让我在每次测试运行中使用任意会话名称。
规格/ utilities.rb
# holds a single test's session name's, mapped to pooled session names
$capybara_session_mapper = {}
# called after each test,
# to make sure each test run has it's own map of session names
def reset_session_mapper
$capybara_session_mapper.clear
end
# manages the mapped session name
def mapped_session_name(session_name)
return :default if session_name == :default # special treatment for the built-in session
$capybara_session_mapper[session_name] ||= $capybara_session_mapper.length
end
# in place of ever using Capybara.session_name directly,
# this utility is used to handle the mapping of session names in a way across all tests runs
def in_client(name)
Capybara.session_name = mapped_session_name(session_name)
yield
end
在* spec_helper.rb *:
config.after(:each) do
Capybara.reset_sessions!
reset_session_mapper
end
直接使用in_client而不是Capybara.session_name的示例测试:
it "can't see a private thing until it is made public" do
in_client(user1.id) do
visit '/some/private/thing'
expect(page).to have_selector('#private-notice')
end
in_client(user2.id) do
visit '/expose/some/private/thing'
end
in_client(user1.id) do
visit '/some/private/thing`
expect(page).to have_selector('#private-content')
end
end