_ruby
Example
Before we get started we'll need to download a copy of BrowserMob Proxy. Once we have that, we'll want to include our requisite libraries:
selenium-webdriver
to control the browserbrowsermob/proxy
to configure/user BrowserMob Proxyrspec=expectations
andRSpec::Matchers
for assertionsjson
to consume JSON data for the performance checks
After that, we can create methods to configure the proxy server (configure_proxy
), set the browser profile to use the proxy server (browser_profile
), pull these together so the test will have a working browser that uses the proxy server (setup
), and tear things down after running the test (teardown
).
# filename: performance.rb
require 'selenium-webdriver'
require 'browsermob/proxy'
require 'rspec-expectations'
include RSpec::Matchers
require 'json'
def configure_proxy
proxy_binary = BrowserMob::Proxy::Server.new('./browsermob-proxy/bin/browsermob-proxy')
proxy_binary.start
proxy_binary.create_proxy
end
def browser_profile
browser_profile = Selenium::WebDriver::Firefox::Profile.new
browser_profile.proxy = @proxy.selenium_proxy
browser_profile
end
def setup
@proxy = configure_proxy
@driver = Selenium::WebDriver.for :firefox, profile: browser_profile
end
def teardown
@driver.quit
@proxy.close
end
Next we'll want to tell the proxy server to capture traffic and return a payload (a.k.a. a HTTP Archive, or HAR for short).
def capture_traffic
@proxy.new_har
yield
@proxy.har
end
We then tie this all together with a run
method. It will call setup
, execute test commands while capturing traffic (capture_traffic
), save the HAR to a uniquely named file (which is named with a time stamp), and tear everything down when it's done (teardown
).
def run
setup
har = capture_traffic { yield }
@har_file = "./selenium_#{Time.now.strftime("%m%d%y_%H%M%S")}.har"
har.save_to @har_file
teardown
end
Now we can put all of this to use by exercising a feature of our application with some Selenium commands.
run do
@driver.get 'http://the-internet.herokuapp.com/dynamic_loading/2'
@driver.find_element(css: '#start button').click
Selenium::WebDriver::Wait.new(timeout: 8).until do
@driver.find_element(css: '#finish')
end
end
If we run this script (e.g., ruby performance.rb
from the command-line) then we will see the browser load, complete some actions, and close. After which, a HAR file will appear in the working directory.
This outputted file is what we'll use to perform some simple benchmark checks.
Rather than identify specific benchmarks to check, let's run through a gamut of them by leveraging a pre-existing benchmarking tool like YSlow. Fortunately, there is a command-line YSlow tool that can consume a HAR file and provide us with useful output.
It's a Node.js app. So first we'll need to install Node.js, and then install the app (with npm install yslow -g
).
After that, we can run it from the command line like so:
yslow --info basic --format plain example.har
This will consume a HAR file and output some helpful information -- including an overall score.
size: 476.8K (476888 bytes)
overall score: A (99)
url: http://the-internet.herokuapp.com/dynamic_loading/2
# of requests: 16
ruleset: ydefault
This overall score is what we are interested in. To get at it, we'll need to change the format type from plain
to json
.
yslow --info basic --format json example.har
This will return a Hash that we can then easily parse through to get the value we want (e.g., the overall score with a key of "o"
).
{"w":476887,"o":99,"u":"http%3A%2F%2Fthe-internet.herokuapp.com%2Fdynamic_loading%2F2","r":16,"i":"ydefault"}
Now we can automate the YSlow command-line execution and perform an assertion by adding the following to the end of our script.
performance_results = JSON.parse `yslow --info basic --format json #{@har_file}`
performance_grade = performance_results["o"]
performance_grade.should be > 95
Now when we run this if the overall score drops below a 95 out of 100 then the test will fail.
From here we can wire this up to a Continuous Integration server and run it headlessly (either with Xvfb or GhostDriver) to perform these checks in an ongoing basis.
Expected Behavior
- Load the browser
- Capture all requests through the proxy server
- Save the captured requests to a HTTP Archive (HAR) file on disk
- Run the HAR file through YSlow to get a numeric grade
- Assert that the grade is above a certain level
Summary
You can see the full code example here.
For more insights into what HAR is and the many uses of it, check out this write-up and video from Ilya Grigorik's blog. You can also check out the HAR spec. And there's also a great presentation from David Burns and David Henderson at GTAC 2009 on using Selenium to do performance benchmarking.
Happy Testing!