Using Ruby to Automate Windows GUI Applications for Testing

Presenting Win32-autogui. A Ruby Win32 GUI testing framework packaged as a RubyGem.

Overview

Win32-autogui provides a framework to enable GUI application testing with Ruby. This facilitates integration testing of Windows binaries using Ruby based tools like RSpec and Cucumber regardless of the language used to create the binaries.

The source code repository is available here: http://github.com/robertwahler/win32-autogui. The repository contains specs and an example Win32 program with source and specs written in Delphi (Object Pascal).

Driving the Window's Calculator Application with IRB

Here is a quick demo using the Ruby Interactive Shell (IRB) under Cygwin on Windows XP to drive "calc.exe."

Install the Gem

Win32-autogui is available on RubyGems.org

gem install win32-autogui

IRB Session

Start up IRB

irb

Paste the following lines into your shell's IRB session.

Note: Window's "calc.exe" is used as the target binary by Win32-autogui's internal specs. The complete source to the wrapper is available here: spec/applications/calculator.rb.

    require 'win32/autogui'
    include Autogui::Input

    class Calculator < Autogui::Application
      def initialize
        super :name => "calc", :title => "Calculator"
      end
      def edit_window
        main_window.children.find {|w| w.window_class == 'Edit'}
      end
    end

Now we can start up the calculator

calc = Calculator.new
calc.running?

Session screenshot

Driving the calculator in IRB (1)

Driving the calculator in IRB (1)

Get some information

calc.pid
calc.main_window.window_class
calc.main_window.children.count

Perform a calculation

calc.set_focus; type_in('2+2=')

Get the result

calc.edit_window.text

Shut it down

calc.close
calc.running?

Session screenshot

Driving the calculator in IRB (2)

Driving the calculator in IRB (2)

RSpec + Win32-autogui for Testable GUI Specifications

The Win32-autogui repository contains an example Win32 program with source, testable binary, and specs written in Delphi (Object Pascal) located here: http://github.com/robertwahler/win32-autogui/tree/master/examples/quicknote.

Quicknote is a bare bones notepad clone. Here is the spec file spec/form_splash_spec.rb for the splash screen functionality.

    require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')

    include Autogui::Input

    describe "FormSplash" do
      after(:all) do
        if @application.running?
          @application.splash.wait_for_close if @application.splash
          @application.file_exit 
          # still running? force it to close
          @application.close(:wait_for_close => true)
          @application.should_not be_running
        end
      end

      describe "startup with no command line parameters" do
        before(:all) do
          # --nosplash is the default, turn it back on
          @application = Quicknote.new :parameters => ''
          @application.should be_running
        end

        it "should show" do
          @application.splash.should_not be_nil
        end
        it "should close within 5 seconds" do
          @application.splash.should_not be_nil
          seconds = 5
          timeout(seconds) do
            @application.splash.wait_for_close
          end
          @application.splash.should be_nil
        end
      end

      describe "startup with '--nosplash' command line parameter" do
        it "should not show" do
          @application = Quicknote.new :parameters => '--nosplash'
          @application.should be_running
          @application.splash.should be_nil
        end
      end

    end

The Quicknote.exe application wrapper. Each of the testable application windows must be defined in a subclass of Autogui::Application. Partial code from lib/quicknote.rb.

    class Quicknote < Autogui::Application

      def initialize(options = {})
        # relative path to app using Windows style path
        @name ="exe\\quicknote.exe"  
        defaults = {
                     :title=> "QuickNote -", 
                     :parameters => '--nosplash', 
                     :main_window_timeout => 20
                   }
        super defaults.merge(options)
      end

      def edit_window
        main_window.children.find {|w| w.window_class == 'TMemo'}
      end

      def status_bar
        main_window.children.find {|w| w.window_class == 'TStatusBar'}
      end

      def dialog_about
        Autogui::EnumerateDesktopWindows.new.find do |w| 
          w.title.match(/About QuickNote/) && (w.pid == pid)
        end
      end

      def splash
        Autogui::EnumerateDesktopWindows.new.find do |w| 
          w.title.match(/FormSplash/) && (w.pid == pid)
        end
      end

      def message_dialog_confirm
        Autogui::EnumerateDesktopWindows.new.find do |w| 
          w.title.match(/Confirm/) && (w.pid == pid)
        end
      end

      # Title and class are the same as dialog_overwrite_confirm
      # Use child windows to differentiate
      def dialog_overwrite_confirm
        Autogui::EnumerateDesktopWindows.new.find do |w| 
          w.title.match(/^Text File Save$/) && 
            (w.pid == pid) && 
            (w.window_class == "#32770") &&
            (w.combined_text.match(/already exists/))
        end
      end

      # Title and class are the same as dialog_overwrite_confirm
      def file_save_as_dialog
        Autogui::EnumerateDesktopWindows.new.find do |w| 
          w.title.match(/Text File Save/) && 
            (w.pid == pid) &&
            (w.window_class == "#32770") &&
            (w.combined_text.match(/Save \&in:/))
        end
      end

      ...

Autotesting Quicknote with Watchr

Watchr provides a flexible alternative to Autotest.

NOTE: The following assumes a global setting of 'git config core.autocrlf input' and that you want to modify the Delphi 7 source to Quicknote which requires CRLF line endings.

Grab the source for Quicknote

cd ~/workspace
git clone http://github.com/robertwahler/win32-autogui -n
cd win32-autogui
git config core.autocrlf true
git checkout

Install watchr

gem install watchr

Run watchr

watchr spec/watchr.rb

Watchr will now watch the files defined in 'spec/watchr.rb' and run RSpec or Cucumber, as appropriate.

Session screenshot

Watchr session running form_splash_spec.rb

Watchr session running form_splash_spec.rb

For more information, please consult the source: http://github.com/robertwahler/win32-autogui.

article comments powered by Disqus

Copyright 1999-2013, GearheadForHire, LLC iconGearheadForHire, LLC
Site design by GearheadForHire, LLC | v2.3.0