<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>My Other Pants &#187; testing</title>
	<atom:link href="http://myotherpants.com/tag/testing/feed/" rel="self" type="application/rss+xml" />
	<link>http://myotherpants.com</link>
	<description>I left it in my other pants</description>
	<lastBuildDate>Sun, 28 Feb 2010 21:27:58 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Crouching Donny, Iron Cucumber &#8211; An Experiment in Functional Testing</title>
		<link>http://myotherpants.com/2009/09/crouching-donny-iron-cucumber/</link>
		<comments>http://myotherpants.com/2009/09/crouching-donny-iron-cucumber/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 02:00:37 +0000</pubDate>
		<dc:creator>Ball</dc:creator>
				<category><![CDATA[work safe]]></category>
		<category><![CDATA[cucumber]]></category>
		<category><![CDATA[ironruby]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[wpf]]></category>

		<guid isPermaLink="false">http://myotherpants.com/?p=122</guid>
		<description><![CDATA[I accidentally agreed to give a talk later this month.  The subject is IronRuby and it&#8217;s application in the .NET ecosystem.  Seems simple enough.  So, to jazz things up, I want to have a host of demo applications.  This is about one.
A while back, I posted an article with an example [...]]]></description>
			<content:encoded><![CDATA[<p>I accidentally agreed to give a talk later this month.  The subject is IronRuby and it&#8217;s application in the .NET ecosystem.  Seems simple enough.  So, to jazz things up, I want to have a host of demo applications.  This is about one.</p>
<p>A while back, I posted <a href="http://myotherpants.com/2009/06/automatic-for-the-people/">an article with an example of using IronRuby and the White framework</a>.  In it, I appear to have made a promise.  </p>
<blockquote><p>I’ll get to Cucumber. I’ll publish examples. I promise.</p></blockquote>
<p><span id="more-122"></span></p>
<p>I&#8217;m going to talk a lot about Donny.  You&#8217;ll meet Donny, but just be aware, he&#8217;s compiled in Debug, so he&#8217;s a bit shy.  Donny is an app written to give me something to test.  He does nothing of real import, he doesn&#8217;t even save his data to disk.  As for why &#8220;Donny&#8221;, I still don&#8217;t know.  I was in a mood yesterday when outlining my presentation and &#8220;Donny&#8221; stuck.</p>
<p><strong><a href="http://cukes.info/">Cucumber</a></strong> &#8211; n, A functional testing framework for ruby.  Cucumber uses Features and Step Definitions to drive an application via it&#8217;s full stack.</p>
<p>Cucumber does work with IronRuby, but by default it&#8217;s runner has some idiosyncrasies for which you&#8217;ll need to compensate.  The cucumber.bat file lives, for me, in <code>c:\IronRuby\lib\IronRuby\gems\1.8\bin</code>.  Another oddity is that it belives I have a color console.  This is <em>mostly</em> true, but Win32Console doesn&#8217;t work for IronRuby, so you&#8217;ll need to use the <code>--no-color</code> option.  For now.  I have my features in a directory I&#8217;m calling &#8220;features&#8221; with an embedded step definitions directory.  Once I finish the presentation, I&#8217;ll have the whole damn thing published and you can look at it then.  Until then, here&#8217;s the command line I used; <code>cucumber --no-colors features</code>.</p>
<p><strong>Feature</strong> &#8211; n, A tightly formatted Business Natural Language used to describe the preconditions, actions, and expected results in a business scenario.  See also, <a href="http://dannorth.net/whats-in-a-story">Story</a>.</p>
<p>I have two basic scenarios; Donny starts with no data, and Donny moves data from the task form to the task list.</p>
<pre>
Feature: New Task
  In order to correctly bill my client
  as an SEP employee
  I want to add a task to the list

  Scenario: Starting the app
    Then all fields are blank
    And the list contains 0 entries

  Scenario:  Add a new Task
    Given I describe my task as Doing work on the Donny app
    And I'm working on project Academy
    And the day is Monday
    And I worked from 10 to 10:30
    When I press the button
    Then all fields are blank
    And the list contains 1 entry
    And the last entry is Monday 10-10:30 Academy Doing work on the Donny app
</pre>
<p><strong>Step Definition</strong> &#8211; n, a ruby script used to match lines in the Feature BNL to actual executable code.  They can be reused across features.</p>
<p>For each Given, When, or Then I have to have a matching step.  These are essentially ruby functions that use a helper to encapsulate my usage of the White library.  Here is <em>donny_steps.rb</em></p>
<pre name="code" class="ruby">
require 'spec/expectations'
require File.dirname(__FILE__) + "/../../donny_helper.rb"

Before do
  @app = Application.launch "Donny/bin/Debug/donny.exe"
  @win = @app.get_window "Window1"
  @tf = TaskForm.new(@app, @win)
  @tl = TaskList.new(@app, @win)
end

After do
  @win.close
end
Given /I describe my task as (.*)/ do |description|
  @tf.description = description
end

Given "I'm working on project $proj" do |proj|
  @tf.project = proj
end

Given "the day is $day" do |day|
  @tf.day = day
end

Given /I worked from (.*) to (.*)/ do |start_time, end_time|
  @tf.start_time = start_time
  @tf.end_time = end_time
end

When "I press the button" do
  @tf.commit
end

Then "all fields are blank" do
  @tf.description.should be_empty
  @tf.project.should be_empty
  @tf.day.should be_empty
  @tf.start_time.should be_empty
  @tf.end_time.should be_empty
end

Then /the list contains (.*) entr(?:y|ies)/ do |n|
  @tl.task_count.should == n.to_i
end

Then /the last entry is (.*)/ do |result|
  @tl.tasks.last.text.should == result
end
</pre>
<p>Um, you&#8217;re missing a piece.  The part that uses White.  Remember the screens?  This time, I didn&#8217;t call them screens, and I don&#8217;t have a full window proxy, but I still have two helper objects.  Now, with some metaprogramming, I could cut down the code size by defining an attribute and describing the type and automation ID of it&#8217;s associated control, but I&#8217;m lazy.  Maybe for the presentation, but I&#8217;m not making any promises. </p>
<pre name="code" class="ruby">
white_loc = (File.dirname(__FILE__) + "/White_Bin_0.18/")
puts white_loc
$LOAD_PATH << white_loc
require "White.Core.dll"

Application = Core::Application
ComboBox = Core::UIItems::ListBoxItems::ComboBox
ListBox = Core::UIItems::ListBoxItems::ListBox
Window = Core::UIItems::WindowItems::Window
include Core::UIItems

class Window
  def get_button(*args)
    self.method(:get).of(Button).call(*args)
  end
  def get_textbox(*args)
    self.method(:get).of(TextBox).call(*args)
  end
  def get_combobox(*args)
    self.method(:get).of(ComboBox).call(*args)
  end
  def get_listbox(*args)
    self.method(:get).of(ListBox).call(*args)
  end
end
class TaskList
  def initialize(app, win)
    @app = app
    @win = win
  end
  def tasks
    @win.get_listbox('tasklist').items.to_a
  end
  def task_count
    tasks.size
  end
end
class TaskForm
  def initialize(app, win)
    @app = app
    @win = win
  end
  def description
    get_tb 'task'
  end
  def description=(text)
    set_tb 'task', text
  end
  def project
    @win.get_combobox('project').selected_item_text
  end
  def project=(proj)
    @win.get_combobox('project').select proj
  end
  def day
    get_tb 'dayofweek'
  end
  def day=(day)
    set_tb 'dayofweek', day
  end
  def end_time
    get_tb 'endtime'
  end
  def end_time=(et)
    set_tb 'endtime', et
  end
  def start_time
    get_tb 'starttime'
  end
  def start_time=(st)
    set_tb('starttime', st)
  end
  def commit
    @win.get_button('commit').click
  end

  private
  def set_tb(auto_id, value)
    @win.get_textbox(auto_id).set_value value
  end
  def get_tb(auto_id)
    @win.get_textbox(auto_id).text
  end
end
</pre>
<p>And some for some context, Meet Donny!<br />
<a href="http://myotherpants.com/wp-content/uploads/2009/09/Donny.PNG"><img src="http://myotherpants.com/wp-content/uploads/2009/09/Donny.PNG" alt="Donny" title="Donny" width="258" height="176" class="aligncenter size-full wp-image-123" /></a></p>
<p>And, after I enter a task, Donny looks like this.<br />
<a href="http://myotherpants.com/wp-content/uploads/2009/09/Donny1.PNG"><img src="http://myotherpants.com/wp-content/uploads/2009/09/Donny1.PNG" alt="Donny" title="Donny" width="258" height="189" class="aligncenter size-full wp-image-125" /></a></p>
<p>That's really all there is to using Cucumber with IronRuby.  Have fun!</p>
]]></content:encoded>
			<wfw:commentRss>http://myotherpants.com/2009/09/crouching-donny-iron-cucumber/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Automatic, for the People</title>
		<link>http://myotherpants.com/2009/06/automatic-for-the-people/</link>
		<comments>http://myotherpants.com/2009/06/automatic-for-the-people/#comments</comments>
		<pubDate>Sun, 28 Jun 2009 23:34:04 +0000</pubDate>
		<dc:creator>Ball</dc:creator>
				<category><![CDATA[work safe]]></category>
		<category><![CDATA[ironruby]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[white]]></category>

		<guid isPermaLink="false">http://myotherpants.com/?p=79</guid>
		<description><![CDATA[Confession, this is the album where I stopped listening to REM.  Dunno why, because Monster was one of the best albums I never bought.
Let us review our strategy, especially referencing our usage of White.  I find it interesting that Test Complete makes it so hard to &#8220;do the right thing&#8221; as propounded by [...]]]></description>
			<content:encoded><![CDATA[<p>Confession, this is the album where I stopped listening to REM.  Dunno why, because Monster was one of the best albums I never bought.</p>
<p>Let us review our strategy, especially referencing our usage of <a href="http://white.codeplex.com">White</a>.  I find it interesting that Test Complete makes it so hard to &#8220;do the right thing&#8221; as propounded by both Scripting GUI Tests in Ruby and by White.  And just what is that?</p>
<p>The responsibility of the test script is to</p>
<ul>
<li> perform a series of actions and verifications.</li>
<li> allow someone to read the script and understand what the hell is going on.</li>
</ul>
<p><span id="more-79"></span></p>
<p>The first is a gimme.  The second is interesting.  When I have my developer hat on, I believe code is read more often then it is written. Wearing my manual tester hat, I believe the scripts should be clear and show intent.  Tricky scripts are trouble.  They are also a pain to maintain.  So, if automated testing the meeting of these two worlds, the clarity and intent of the scripts must be sacrosanct.  The libraries the scripts use, on the other hand, just need to be treated like code and kept maintainable.</p>
<p>What do I want my test scripts to look like?  There are two options, DSL, or clearly abstracted test code.</p>
<p>First, lets look at DSLs, Baby!  WAHOOO! Tests that double as manual tests!</p>
<pre name="code" class="ruby">
open sekrit with New Document
insert image "picture.png" into sheet
first image item should match stored image "stored_0001.png"
</pre>
<p>I could do that.  I could use some functional programming language.  I could also use something like <a href="http://cukes.info/">cucumber</a> and code behind my feature files.  But what&#8217;s the point?  All I need is clarity, so the auditors / business people understand.  I LIKE dsls, but this buys us nothing right now.</p>
<p>Option two uses Objects to clarify the application.</p>
<pre name="code" class="ruby">
sek = Sekrit.open( :New_Document )
doc = sek.document

doc.add_image("picure.png")
Assert.equal doc.images[0].as_bitmap, Stored.images["0001.png"]
</pre>
<p>This is at the proper level of abstraction for a slightly motivated business user to understand.  What they don&#8217;t care about at this level is the control hierarchy and control manipulation.  Unless the requirements say, &#8220;via a popup menu&#8221; or some such.</p>
<p>If you&#8217;re going to be technical, this is a <a href="http://en.wikipedia.org/wiki/Facade_pattern">facade</a>.  It&#8217;s a wrapper to the complex underbelly of the white framework.  It allows for a higher level use of the collected objects and re-use as we don&#8217;t have to repeat the code for complex actions and interactions.  It also decouples our tests from changes in our application.  I&#8217;ve had to chase that down in our current automation set, and I hate it.</p>
<p>How do we build up this abstraction?  To be compatible with White&#8217;s recommended practices, I&#8217;m going to call this facade a &#8220;Screen&#8221;.  We&#8217;re going to write a test for an application for which we have no source.  Download <a href="http://white.codeplex.com/">blu</a> and warm up your tweetin&#8217; fingers.  We&#8217;re going to log in!</p>
<pre name="code" class="ruby">
# our screens
class Blu
  def initialize(application, window)
    @app = application
    @win = window
  end
  def login_screen
    return LoginScreen.new(@app, @win)
  end
end
class LoginScreen
  def initialize(application, window)
    @app = application
    @win = window
  end
  def login_user( username, password, remember = false)
    @win.get_textbox("UsernameTextBox").enter username
    @win.get_textbox("PasswordTextBox").enter password
    rem = @win.get_checkbox("Rememberage")
    if rem.checked != remember
      rem.enter " "
    end
    @win.get_button("LoginButton").click
  end
end
</pre>
<p>You noticed that the BluScreen has a LoginScreen?  Our application has regions and concepts to which we wish to refer.  For example, we may want to represent a ribbon control, a toolbar, different types of documents, or even the clipboard.</p>
<p>How do we use these screens?  Let&#8217;s flesh out this little story in <a href="http://dannorth.net/whats-in-a-story">Dan North &#8220;Story&#8221; format</a>.</p>
<pre> As I malicious user, so I can't defame Brian's good twitter name,
   Given blu is open
   And no one is logged in
   When I attempt to log in using a bad password
   Then I should see a warning that my login information was incorrect
</pre>
<pre name="code" class="ruby">
app = Application.attach("blu")
win = app.get_window("blu")

blu = Blu.new(app, win)
login = blu.login_screen
login.login_user( "Myotherpants", "NoWai!" )

# A test would have assertion here...
</pre>
<p>I&#8217;m holding out on you. The truth of the matter is, I started with the test steps first, then made screens that abstracted those steps.  But there&#8217;s magic in the screens, they have magic strings passed around like <code name="code" class="ruby">@win.get_checkbox("Rememberage")</code>.  Where did that come from?  I got it from <a href="http://msdn.microsoft.com/en-us/library/ms727247.aspx">UISpy</a>.  I&#8217;ve read about <a href="http://www.codeproject.com/KB/WPF/WoodstockForWPF.aspx">Woodstock</a>, <a href="http://blois.us/blog/2006/08/long-time-since-my-last-post-but-dont_21.html">Snoop</a>, and a few other tools, but UISpy is the only tool I used for this post.  It is in the Windows SDK.  UISpy shows a tree of controls.  When you click on one, it hilights it with a red box.  It also displays information such as the automation Id, those magic strings we have scattered in our code.  Before my two picture tutorial on UISpy, let me note, those strings are what&#8217;s likely to break your script in the future as your application grows.</p>
<div id="attachment_85" class="wp-caption alignnone" style="width: 385px"><a href="http://myotherpants.com/wp-content/uploads/2009/06/uispy-screen.png"><img src="http://myotherpants.com/wp-content/uploads/2009/06/uispy-screen-300x226.png" alt="UI Spy looking at a textbox" title="uispy-screen" width="300" height="226" class="size-medium wp-image-85" /></a><p class="wp-caption-text">UI Spy looking at a textbox</p></div><br />
<div id="attachment_86" class="wp-caption alignnone" style="width: 241px"><a href="http://myotherpants.com/wp-content/uploads/2009/06/blu-screen.png"><img src="http://myotherpants.com/wp-content/uploads/2009/06/blu-screen-171x300.png" alt="Blu when UISpy is indicating a textfiled" title="blu-screen" width="171" height="300" class="size-medium wp-image-86" /></a><p class="wp-caption-text">Blu when UISpy is indicating a textfiled</p></div>
<p>what else is there? </p>
<p>These aren&#8217;t tests, they are automation.  I&#8217;ll eventually wrap the automation with RSpec and get some real tests.  I&#8217;ll get to Cucumber.  <a href="http://myotherpants.com/2009/09/crouching-donny-iron-cucumber/">I&#8217;ll publish examples</a>.  I promise.</p>
<p>But next, I want to address three types of custom controls:<br />
  User controls, Inhereited and Templated Controls, and Framework Elements.  Another problem is finding un-named controls.  I&#8217;ll see you next week.</p>
<p>One last bit, here&#8217;s what the white ruby library is starting to look like.</p>
<pre name="code" class="ruby">
white_loc = (File.dirname(__FILE__) + "\\White_Bin\\")
$LOAD_PATH.push(white_loc)
require "White.Core.dll"

Application = Core::Application
Button = Core::UIItems::Button
CheckBox = Core::UIItems::CheckBox
TextBox = Core::UIItems::TextBox
Window = Core::UIItems::WindowItems::Window
SearchCriteria = Core::UIItems::Finders::SearchCriteria

class Window
  def get_button(*args)
    self.method(:get).of(Button).call(*args)
  end
  def get_button_labeled(label)
    self.get_button(SearchCriteria.by_text(label))
  end
  def get_checkbox(*args)
    self.method(:get).of(CheckBox).call(*args)
  end
  def get_textbox(*args)
    self.method(:get).of(TextBox).call(*args)
  end
end
</pre>
]]></content:encoded>
			<wfw:commentRss>http://myotherpants.com/2009/06/automatic-for-the-people/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Generic White Rubies are Open</title>
		<link>http://myotherpants.com/2009/06/generic-white-rubies-are-open/</link>
		<comments>http://myotherpants.com/2009/06/generic-white-rubies-are-open/#comments</comments>
		<pubDate>Thu, 18 Jun 2009 21:15:23 +0000</pubDate>
		<dc:creator>Ball</dc:creator>
				<category><![CDATA[work safe]]></category>
		<category><![CDATA[ironruby]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[white]]></category>

		<guid isPermaLink="false">http://myotherpants.com/?p=76</guid>
		<description><![CDATA[I&#8217;ve been continuing my exploration of IronRuby and White for gui testing.  I expected to deal with Automation IDs first, but I&#8217;ll get back to that.  For now I&#8217;m tying IronRuby to White, and handling generics.
My install of white is not in the GAC, so I&#8217;ll be requireing DLLs from a directory.  [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been continuing my exploration of <a href="http://myotherpants.com/2009/06/thoughts-on-gui-testing/">IronRuby and White for gui testing</a>.  I expected to deal with Automation IDs first, but I&#8217;ll get back to that.  For now I&#8217;m tying IronRuby to White, and handling generics.</p>
<p>My install of white is not in the GAC, so I&#8217;ll be requireing DLLs from a directory.  DLLs are looked for in ruby&#8217;s <code>$LOAD_PATH</code>, just like ruby libraries.  It&#8217;s an array.  You&#8217;ll notice that White suggests also including an NUnit dll, but I&#8217;ve not needed that with RSpec.  And, I want to shorten the namespace stuff.  So let&#8217;s start with white.rb and we&#8217;ll add to it later.</p>
<pre name="code" class="ruby">
white_loc = "C:\\Projects\\Libs\\White_Bin_0.18"
$LOAD_PATH.push(white_loc)
require "White.Core.dll"
Application = Core::Application
</pre>
<p><span id="more-76"></span></p>
<p>So, next we just start using the application.  I want to launch my application, conviniently called &#8220;sekrit.&#8221;  I need to find the window titled &#8220;Sekrit (version 0.5)&#8221;.  Then I need to call the C# method <code>win.Get&lt;Button&gt;("Open")</code> but that uses generics that ruby doesn&#8217;t have.  Using what I learned from a <a href="http://stackoverflow.com">Stack Overflow</a> post <a href="http://stackoverflow.com/questions/895585/how-to-invoke-an-overloaded-generic-methods-in-ironruby">how to invoke an overloaded generic method in ironruby</a>, we can work around that in IronRuby 0.5.</p>
<pre name="code" class="ruby">
require 'white'
app = Application.launch("c:\\projects\\sekrit\\build\\sekrit.exe")
win = app.get_window("Sekrit (version 0.5)")
win.focus
win.method(:get).of(Core::UIItems::Button).call("Open")
</pre>
<p>Oh, lawdy!  Did you see that last line?  It ain&#8217;t pretty.  This is something we&#8217;ll be doing a lot of, so let&#8217;s wrap that up.  I need to add, essentially, a non-generic extention method to wrap the generic call.  But, do it with Ruby to extend a .NET class.  Back to white.rb for some open class magic.</p>
<pre name="code" class="ruby">
class Core::UIItems::WindowItems::Window
  def get_button(*args)
    self.method(:get).of(Core::UIItems::Button).call(*args)
  end
end
</pre>
<p>Now that cleans up our earlier program.</p>
<pre name="code" class="ruby">
require 'white'
app = Application.launch("c:\\projects\\sekrit\\build\\sekrit.exe")
win = app.get_window("Sekrit (version 0.5)")
win.focus
win.get_button("Open")
</pre>
<p>Okay, one more problem.  I talked about RSpec, but that&#8217;s because I hacked my install.  There&#8217;s a known bug in IronRuby 0.5&#8217;s implementation of <code>File.expand_path(file_name)</code> that uses the .NET System::IO::Path methods that throws execptions when you try to expand a path with &#8220;:8&#8243; on the end to help track line numbers.  I don&#8217;t know yet if it&#8217;s been fixed.  If not, that may be another post.</p>
<p>So, what&#8217;s left?  RSpec doesn&#8217;t run out of the box.  I need to wrap some stuff up so I can say <code> app.open_file("some_file.ext") </code> and other higher level &#8220;user action&#8221; concepts (those shouldn&#8217;t be in white.rb, but sekrit.rb).  I need to handle finding controls quickly and easily.  I&#8217;ll take a look at that this weekend and see what I can find.  Especially, since I&#8217;ll be hanging with a WPF MVP both this evening at IndyALT.NET and on Saturday.</p>
]]></content:encoded>
			<wfw:commentRss>http://myotherpants.com/2009/06/generic-white-rubies-are-open/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Thoughts on GUI Testing</title>
		<link>http://myotherpants.com/2009/06/thoughts-on-gui-testing/</link>
		<comments>http://myotherpants.com/2009/06/thoughts-on-gui-testing/#comments</comments>
		<pubDate>Mon, 15 Jun 2009 11:03:42 +0000</pubDate>
		<dc:creator>Ball</dc:creator>
				<category><![CDATA[work safe]]></category>
		<category><![CDATA[ironruby]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[white]]></category>

		<guid isPermaLink="false">http://myotherpants.com/?p=70</guid>
		<description><![CDATA[I&#8217;m currently involved with a WPF project as a tester.  My charge is to automate the System-Level testing of this project for my client.  Our belife is that automated testing allows us to find &#8220;popup bugs&#8221; before they become a problem.  This has worked well, in combination with the team doing a degree of dog-fooding. [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m currently involved with a WPF project as a tester.  My charge is to automate the System-Level testing of this project for my client.  Our belife is that automated testing allows us to find &#8220;popup bugs&#8221; before they become a problem.  This has worked well, in combination with the team doing a degree of dog-fooding.  They catch the esoteric things, I find the simple things no one looks for.  Also, I&#8217;m currently working with a lot of them as we build manual test scripts for our verification phase.  This is a lot more focused act that, once automated as we move forward with version two, will allow us to have a better understanding of the &#8220;shipability&#8221; of our software.  We&#8217;re regulated and we want to automate most of the acceptance testing, at least in theory.</p>
<p><span id="more-70"></span></p>
<p>I&#8217;ve been using TestComplete for this.  T.C. is good stuff, but there are some things about it I don&#8217;t like.  It&#8217;s meant for recording and playback of tests.  But, to automate in a regulated situation, I don&#8217;t want to see javascript (T.C.&#8217;s CSharp script is a horrible trap, don&#8217;t go there) like the following</p>
<pre name="code" class="javascript">var p1;
var w1;
p1 = Sys.Process('MyProcess');
w1 = p1.Window('HWind: MainWindow').MainWindow.Base.WPFObject('Grid', '', 1).ScrollView;
w1.x = 0;
w1.y = 0;
w1.WPFObject('RowItem', '', 2).StackPannel.WPFObject('Button', 'Cancel', 1).Click(3,15);</pre>
<p>What the hell is my intent here?  Also, I&#8217;m crawling the visual tree, which may be brittle.  The renaming of internal variables, like &#8220;StackPannel&#8221; to something more revealing like &#8220;VisibleFlarns,&#8221; I&#8217;d have to go edit this test.  And a buch of other tests that traverse that point in the tree.  We kind of saw this coming and have rewritten our tests to a degree.</p>
<pre name="code" class="javascript">var process = Sys.Process('MyProcess');
VisibleFlarn(process, 2).WPFObject('Button', 'Cancel', 1).Click();</pre>
<p>This is slightly more clear.  The main benefit is that we&#8217;re hiding the traversal of the tree to the visible flarns.  That means we only have one place to hunt down our changes to the tree.  But it doesn&#8217;t take full advantage of our environment, JavaScript.  Foreign objects, like the process, windows, and buttons can&#8217;t be extended with helper methods.  So, I&#8217;ve started the next round of testing with a bunch of decorators and strict reuse.</p>
<pre name="code" class="javascript">var process = new MyProcess();
process.GetVisibleFlarn(2).Cancel();</pre>
<p>That&#8217;s starting to get to good.  The last piece is that regulatory oversight loves positive passing of tests, not just error logs.  T.C. doesn&#8217;t have that.  T.C. doesn&#8217;t even really have asserts.  You can only error, or log.  In fact, I&#8217;ve yet to find a test framework that does that out of the box.   Even those that assert, don&#8217;t log positive asserts.  Why is this important?  I want to be able to say Req-123 was tested 7 times, and passed each one.  That&#8217;s what the oversight wants.  They fear, &#8220;Well, it&#8217;s didn&#8217;t show up in the error logs, so I&#8217;m assuming it worked.&#8221;  So, I wrote some asserts that take explicit requirements and &#8220;Why&#8221; I&#8217;m asking about that.</p>
<p>Now, on to prong two, of my assault.</p>
<p>I recently picked up &#8220;<a href="http://pragprog.com/titles/idgtr/scripted-gui-http://pragprog.com/titles/idgtr/scripted-gui-http://pragprog.com/titles/idgtr/scripted-gui-testing-with-ruby">Scripted GUI Testing with Ruby</a>&#8221; by Ian Dees as I visited my local book store. I like the book. It covers using Win32API to grab window handles and throw around events. Oh, it&#8217;s also got some crap about Jruby and an apple-talk bridge if you want to go that route. Basically, it covers testing on all the platforms that aren&#8217;t X11 or .NET. That doesn&#8217;t detract from the book&#8217;s handling of GUI testing strategy, but I want to fill in that gap.</p>
<p>The CLR has a pretty good testing story, for WPF at least, in the <a title="White" href="http://white.codeplex.com">White </a>testing framework from ThoughtWorks.  It uses Automation Ids to identitfy and find all of your controls.  So, the pieces I&#8217;m looking at are, &#8220;What are Automation Ids,&#8221; and &#8220;What are their best practices?&#8221;  Couple that with a running example of using IronRuby to get my hands on the application and bang it around.  The big deal is our current project doesn&#8217;t use Automation Ids (accessibiltiy isn&#8217;t a huge driving need), so I need to show some benefit and low risk.</p>
<p>What am I going to have to do, for this experiement?  I&#8217;m, currently, only interested in rSpec and don&#8217;t need cucumber.  I&#8217;ll start by using White directly, but I&#8217;m guessing I&#8217;ll be wrapping it some.  I&#8217;m also interested in alternatives to AutomationIds.  But I&#8217;ll need to wrap the standard asserts with something that positively checks asserts against requirement numbers.</p>
<p>Will the regulators go for this?  I don&#8217;t know.  When working in a regulated environment, you can be innovative with how you handle testing as long as the auditors are comfortable with your ability to be repeatable and cover what they find important.</p>
<p>Should be fun.</p>
]]></content:encoded>
			<wfw:commentRss>http://myotherpants.com/2009/06/thoughts-on-gui-testing/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
