Automated testing of websites via “real” users.

Of all the testing we can do, there’s nothing quite like firing up your browser and navigating to the website in question, logging in and doing stuff. All of the integration tests, port tests, contrived “I’m alive” tests etc can give you an *indication* that your website code is all well and good. However what you really want to test is “can I jump to it, do x y z action, and complete those actions without it bombing out”. We have a two options, we hire an army of minions who will do that for us every 15minutes on the dot OR we could do it automatically. How do we do this ?

Well there are a number of ways. One option I’m going to walk through is using the magic genius of Safari Watir, RSpec tests, ruby, a few gems, cron and any Mac you can lay your hands on. We set this up a while ago monitoring some of our sites and it’s great for finding out when something in your webstack has fallen over. For a < $1k investment it's a no brainer for any web site.

Caveat - this ain't going to test your flash/flex content - this is just for HTML based sites. Read on...

1. Machine setup

First, take one mac mini. We need to install ruby, ruby gems, rails, rspec, safariwatir, and rb-applescript bridge on it. Follow the Hivelogic narrative here for instructions on installing a full rails stack. Then just simply run these commands to finish off the last remaining gems.

  sudo gem install rspec
  sudo gem install safariwatir --include-dependencies

2. First website check

So we’ve got our infrastructure setup. Now we need to write the scripts that actually run the test the site. These will fire up safari and tell it to navigate to various URL’s, then check the content on the pages returned. So in true behaviour driven development style we write a spec that in plain english walks through the steps. It fires up a browser instance courtesy of Watir::Safari.new and uses it to navigate around pages. First let’s create a file called check_google.rb like so:

require 'rubygems'
require 'safariwatir'
 
context "With www.google.com" do
  before(:all) do
    @browser = Watir::Safari.new
  end
 
  it "can navigate to home page" do
    @browser.goto("http://www.google.com/")
  end
 
  it "homepage should not have a 404" do
    @browser.contains_text("404").should == nil
  end
 
  #it "should throw an contrived error, when seeing if yahoo is on main page" do
  #  @browser.contains_text("www.yahoo.com").should == true
  #end
 
  after(:all) do
    @browser.close
  end
end

Now if we run

spec check_google.rb

we get output as follows:

 RowanH$ spec check_google.rb
..

Finished in 2.818356 seconds

2 examples, 0 failures

Fantastic, it’s what we expect google is alive and tickety-boo. Now to check the failure scenario, uncomment the yahoo test:

RowanH$ spec check_google.rb
..F

1)
'With www.google.com should throw an contrived error, when seeing if yahoo is on g main page' FAILED
expected: true,
     got: nil (using ==)
./test_mysite.rb:18:

Finished in 2.837444 seconds

Cool, we know what a failure looks like.

3. Turning your console output into a email message

We’re not going to be logging in and doing this all the time, so we want to be emailed of success/failures. We are going to use a custom formatter for RSpec, which can make our output look a lot more interesting and pop it into an email. As I was running these scripts on a machine with a full rails stack I used ActiveMailer for sending emails.. (you’ll see why in a minute) so let’s create a custom formatter that will format our output for mailing. Lets call it mail_formatter.rb and pop it into the same place as our existing scripts - as follows.

require 'rubygems'
require 'action_mailer'
 
#actual email thingy
ActionMailer::Base.server_settings[:address] = 'domain@myhost.com'
class Emailer < ActionMailer::Base
  def test_email(text, status)
    subject    "TEST Autotest Status - #{status}"
    from       "mytestbox@myhost.com"
    recipients "me@myhost.com"
    body       text
  end
end
 
class MailFormat < Spec::Runner::Formatter::BaseTextFormatter
  def start(spec_count)
    @mail_output = String.new
    @mail_output << "Test started \n"
    @mail_status = "Tests OK"
  end
 
  def add_behaviour(name)
    @mail_output << "\n #{name}\n"
  end
 
  def example_failed(example, counter, failure)
    @mail_output << " - #{example.description} FAILED \n"
    @mail_status = "#{counter} tests FAILED"
  end
 
  def example_passed(example)
    @mail_output << " - #{example.description} PASSED \n"
  end
 
  def dump_summary(duration, spec_count, failure_count, something_else)
    @mail_output << "\n"
    @mail_output << "Finished in #{duration} seconds "
    @mail_output << "#{spec_count} test#{'s' unless spec_count == 1}, #{failure_count} failure#{'s' unless failure_count == 1}"
    Emailer.deliver_test_email(@mail_output, @mail_status)
  end
end

Right so this time if we a new command like so, to require the mail_formatter, and output in mail format, we should by rights receive an email:

 RowanH$ spec check_google.rb -r mail_formatter.rb -f MailFormat

1)
'With www.google.com should throw an contrived error, when seeing if yahoo is on main page' FAILED
expected: true,
     got: nil (using ==)
./test_mysite.rb:18:

(we still get our console output if we get a failure)

5. Automating it

Okay so wrap that lot up in a shell script, and call it via cron (hey I’m not going to write *everything* out here), and you’ve now got a simple script that’s calling up your website and checking it.

6. Extending it

If you browse around for some of the safari-watir examples out there then you’ll see more of how to access specific fields and named form elements - this will let you actually login and do stuff on your site(s) your testing.

7. Extra Credit - Screenshots!!

Okay, we’ve got our system emailing us every test. But what would be really cool is if it actually sent us a screenshot everytime something turned to custard and failed so we could see what actually went wrong. Well… it’s suprisingly easy. We’re going to use OSX’s inbuilt screencapture utility and fire off a shell command to capture a png file everytime something goes wrong. Then pop those in as attachments to our status email.
Modify the code like so:

In the Emailer.test_mail method, add a parameter images, and pop this code at the bottom of the method:

   if ( images )
      for image_name in images
        attachment :content_type => "image/png", :filename => image_name ,
                        :body => File.read("/Users/rowanh/Desktop/failed_images/#{image_name}")
      end
    end

So this will allow our email method to read in a list of images and attach them to mail message. Next we want to update our formatter.

For the start method add the following:

    @failed_image_count = 0
    @failed_images = Array.new

Add a new method like so :

  def take_screenshot()
    @failed_image_count += 1
    screenshot_name = "failure_#{@failed_image_count}.png"
    system "screencapture /Users/rowanh/Desktop/failed_images/#{screenshot_name}"
    @failed_images << screenshot_name
  end

Next update example_failed so it takes_screenshot.

Finally in the deliver_test_email method, pop in the @failed_images array.

Conclusion

Bingo! you now have a hugely useful tester, that runs away, tests your website, tells you and will actually show you what went wrong. For not a whole lot of investment.

Off to setup a continuous integration machine that actually does this for each build……..

Credit:
http://blog.aslakhellesoy.com/2006/12/2/getting-screenshots-from-watir
http://redsquirrel.com/cgi-bin/dave/projects/watir

No Comments, Comment or Ping

Reply to “Automated testing of websites via “real” users.”

About

Rowan is a Product Development Manager, specialising in architecting, developing and putting web applications into production - in particular Ruby on Rails based apps. He lives in Toronto, Canada but speaks in a funny accent as he's originally from New Zealand. He's been working in the software and web business for over a decade. This blog covers Web Application development and deployment in the real world, dealing with topics from business fundamentals to Ruby on Rails, Merb, PHP, Flex, MySQL, Apache and more.

Read more ...

 

 

View Rowan Hick's profile on LinkedIn

 

Subscribe to my RSS feed