Programmatically take screenshot in IronRuby

After figuring out how to take a screenshot using .Net, I translated the C# I came up with to IronRuby. Now, when any of my IronRuby-powered tests fail, I take a screenshot – saves loads of time when trying to work out why a test failed!

Here’s the code you need:


require 'System.Drawing'
require 'System.Windows.Forms'

bitmap = System::Drawing::Bitmap.new(
        System::Windows::Forms::Screen.PrimaryScreen.Bounds.Width,
        System::Windows::Forms::Screen.PrimaryScreen.Bounds.Height,
        System::Drawing::Imaging::PixelFormat.Format32bppArgb)

System::Drawing::Graphics.FromImage(bitmap).CopyFromScreen(
        System::Windows::Forms::Screen.PrimaryScreen.Bounds.X,
        System::Windows::Forms::Screen.PrimaryScreen.Bounds.Y,
        0,
        0,
        System::Windows::Forms::Screen.PrimaryScreen.Bounds.Size,
        System::Drawing::CopyPixelOperation.SourceCopy)

bitmap.Save("c:\\screenshot.png", System::Drawing::Imaging::ImageFormat.Png)

A screenshot is taken of the primary screen (and *only* the primary screen) and is saved as a PNG to c:\screenshot.png . Modify to your heart’s content.

Hole-in-the-open-source-market Alert: cross platform gem for taking screenshots. Please don’t make me write it!

Testing a website on different versions of IE

So, no matter how much you argue that it’s an ancient, irrelevant browser; there’s no way you can wriggle out of having to test your web app against IE6 on WinXP. But… trying to find a machine with it lying around might be difficult. Magnanimous Microsoft have made testing your web app on different IE/Windows combinations less tedious than it could be: combine Virtual PC with a collection of pre-built images and you’re on your way. Here are the details…

First, you’ll need to install Virtual PC:

  • Download the latest version of Virtual PC from here if you’re running Windows 7
  • Download Virtual PC 2007 from here if you’re running Windows XP/Vista

Next, you’ll need to download as many of the following combinations of Windows/IE as you want from here.

The Windows/IE combinations available are:

  • IE6 / XP SP3
  • IE7 / XP SP3
  • IE7 / Vista SP1
  • IE7 / Vista SP2
  • IE7 / Vista SP3
  • IE8 / XP SP3
  • IE8 / Vista SP1
  • IE8 / Vista SP2
  • IE8 / Vista SP3

Download the images you need, start them, get your testing done before the VM runs out of time (they’re time limited) and then get back to doing something less painful!

Enjoy your multi-IE-version testing. Rather you than me ;)

How to connect to an Oracle database in IronRuby

After spending a few hours trying to connect to an oracle database in ironruby using various gems, I gave up. None of the gems out there would work, each for a different reason. It was time to write my own class to do the job of managing connections and executing queries.

You’ll need a few things:

  1. A copy of the ‘Oracle.DataAccess.dll’ that you can find somewhere inside this outrageously large download:
    http://www.oracle.com/technology/software/tech/windows/odpnet/index.html
    Copy the ‘Oracle.DataAccess.dll’ into your load path (you’ll find it somewhere in the bowels of the directory structure that the above installs)
  2. An oracle database you can point at
  3. The connection string required to connect to the database. It’ll look something like:
    Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROT...

Once you’ve got those details, you can use the following class:

require 'System'
require 'System.Data'
require File.join(File.expand_path(File.dirname(__FILE__)), "Oracle.DataAccess.dll")

class IronRubyOracleClient
  #pass in oracle connection string, eg, for Test env:
  def initialize(connection_string)
    @connection = Oracle::DataAccess::Client::OracleConnection.new(connection_string)
  end

  #opens connection
  def open
    @connection.open
  end

  #returns 2D array
  def execute(query)
    @query = query
    cmd = Oracle::DataAccess::Client::OracleCommand.new(@query, @connection)
    cmd.CommandType = System::Data::CommandType.Text
    data_reader = cmd.ExecuteReader()
    column_count = data_reader.visible_field_count.to_i

    result_rows = ::System::Collections::ArrayList.new

    while(data_reader.read) do
      row = ::System::Collections::ArrayList.new
      column_count.times do |i|
        row.add(data_reader.get_oracle_value(i).to_string)
      end
      result_rows.add(row)
    end

    result_set = []

    result_rows.each do |result_row|
      ruby_row = []
      result_row.each do |cell|
        ruby_row << cell.to_s
      end
      result_set << ruby_row
    end

    result_set
  end

  #close connection
  def close
    @connection.close
  end
end

And here’s how you use it:


#create your connection string
connection_string  = "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=..." #etc...
#create an instance of the client, passing in the connection string
my_client = IronRubyOracleClient.new(connection_string)
#open a connection to the database
my_client.open
#execute a query and save the result
results = my_client.execute("select * from some_table")
#dump the results (a 2D array of values)
puts results.inspect
#close the connection
my_client.close

It’s fairly slow, but it works. Which is an improvement on what’s out there…

Note that everything is returned as a string. For some reason, the unless the data is a basic string or is a number that fits into an integer, the data gets garbled somewhere between the dll and ironruby. I can’t find out where, so everything-returned-as-a-string is the current compromise. If you can get it to work with all data types, send it along!

Explaining Watir, Selenium and WebDriver

Something I seem to be explaining to people all the time… the relationships between Watir, Watir “2.0″, Selenium, Selenium “2.0″ and WebDriver.

Alister Scott has done an excellent job of explaining the impact of WebDriver on Selenium and Watir and what it mean for their respective futures. Read it here.

Summary:

  • Selenium 1 => dead
  • Selenium 2 == WebDriver
  • Watir 1.* (+ derivs) => dead
  • Watir 2.0 => Watir API using WebDriver to communicate with the browser

===Update===
Added version number to Watir to avoid the confusion seen here.

Testing redirects with ruby

—UPDATE—
Since writing this post, I’ve put together a gem called ‘responsalizr‘ which is a way better solution than what follows in this post. Read about it here. And now back to the original post…

Testing redirects from a web app is simple enough – make a request and check the response code making sure it’s a 301, 302 or whatever you’re expecting. The test you end up writing isn’t nice idiomatic ruby though. So, I wrote a quick monkey patch… here it is:

class Net::HTTPResponse
  #returns true if the response is a 200
  def ok?
    instance_of?(Net::HTTPOK)
  end

  #returns true if the response is a 301
  def found?
    instance_of?(Net::HTTPFound)
  end

  #returns true if the response is a 302
  def moved_permanently?
    instance_of?(Net::HTTPMovedPermanently)
  end

  #returns true for any kind of redirect (301..307)
  def redirect?
    kind_of?(Net::HTTPRedirection)
  end

  #returns the url being redirected to if this response is a redirect
  def redirect_url
    redirect? ? self['location'] : raise("Not a redirect response")
  end
end

Basically, it adds the following predicate methods to the Net::HTTPResponse class: “ok?” (returns true if response code is 200), “found?” (returns true if response code is 301), “moved_permanently?” (returns true if response code is 302) and “redirect?” (returns true if the response is a redirect – from 301..307). Because these are predicate methods, they can be used by rspec – your test code suddenly becomes much cleaner! The moneky patch also adds the “redirect_url” method which returns the url to be redirected to if the response is a redirect of some sort. The advantage of this is that your tests become much more idiomatic:


#the urls we're testing with...
@url_initially_navigated_to = "http://mail.google.com"
@expected_redirect_url = "https://www.google.com/.../etc/..."

#make the request
@response= Net::HTTP.get_response(URI.parse(@url_initially_navigated_to))

#nice idiomatic tests! - use the one you're expecting...
@response.should be_ok                #expecting a 200
@response.should be_found             #expecting a 301
@response.should be_moved_permanently #expecting a 302
@response.should be_a_redirect        #expecting anything between 301..307

#testing the url being redirected to
@response.redirect_url.should match(@expected_redirect_url)

There you go! Nice idiomatic redirect tests! Enjoy.

Remove junk from IronRuby cucumber output

When running cucumber tests under IronRuby, your output will be full of junk like the following:


Feature: example feature

Scenario: a scenario←[90m     # features\testoutput.feature:3←[0m
←[32mGiven some test setup←[90m  # features/step_definitions/output_steps.rb:1←[0m←[0m
←[32mWhen I do something←[90m    # features/step_definitions/output_steps.rb:5←[0m←[0m
←[32mThen something happens←[90m # features/step_definitions/output_steps.rb:9←[0m←[0m

1 scenario (←[32m1 passed←[0m)
3 steps (←[32m3 passed←[0m)
0m0.160s

This is not great. All those “[32m” things make the output difficult to read and cause (me at least) some serious distraction. Thankfully, it’s easily fixed… if you add the –no-color option when you call the icucumber command, ie:

icucumber --no-color

…the output will change to be:


Feature: example feature

Scenario: a scenario     # features\testoutput.feature:3
Given some test setup  # features/step_definitions/output_steps.rb:1
When I do something    # features/step_definitions/output_steps.rb:5
Then something happens # features/step_definitions/output_steps.rb:9

1 scenario (1 passed)
3 steps (3 passed)
0m0.260s

Much better, and easily solved!

RQuery: A thin layer of JQuery over watir/selenium

So I went to a presentation today, run by Aidy Lewis and Josh Chisholm about Josh’s new RQuery project; here’s a braindump of what I remember.

RQuery is not supposed to be a competitor to Selenium or Watir but builds on top of it to provide a few things… the ones that interested me were the ability to query for objects by using css selectors, and the fact that it converts ruby into javascript so that very little work is done inside the browser.

The css selector stuff is done by injecting jQuery into the page that’s being tested (if it’s not already there). This is pretty cool because it means you don’t need to worry about browser specific ways to select stuff (useful, since watir and selenium are/are going to be sat on top of webdriver so browser agnosticism is important). It also means that you don’t need to know xpath – cool if you’re a webdev since you don’t want to learn something new, and you probably already know css!

The ruby-to-javascript stuff also looks pretty cool: instead of running loads of ugly javascript in the browser, the ruby code in your test is converted to some simple jQuery and that is what gets executed. Interesting to note that in the demo we saw, the tester (sorry, didn’t catch your name!) mentioned that the only downside to this is when debugging – did the error occur in ruby? In the ruby-javascript translation? In the CSS? In the browser? In the AUT?

Check out the rQuery wiki for how to get started.

Overall, RQuery looks like a cool project. I’ll be following it for sure…