SlideShare a Scribd company logo
1 of 46
First Stop
on the
Book Tour
Powell’s Books
November 13, 2008
Why I’m an idiot and you
shouldn’t buy my book
“Yes, but...”
#1
Capture / playback is yucky
MoveMouse(125, 163);
Delay(0.65);
LeftButtonDown();
Delay(0.074);
LeftButtonUp();
GetWindowText(hCtrl, buffer, bufferSize);
if (0 != lstrcmp(buffer, Lquot;Some textquot;))
LOG_FAILURE(quot;Text didn't matchnquot;);
Delay(0.687);
MoveMouse(204, 78);
//
// ...and so on, for pages and pages
Capturing the wrong things!
Model-based testing
Dr. Atif Memon, UMD
http://www.cs.umd.edu/~atif/GTAC08
follows




Capture the relationships
An interaction follows another interaction
Markov your activity log
http://www.codeodor.com/index.cfm/2007/11/7/
Fun-With-Markov-Models/1701
a ball
a ball
a red ball
require 'enumerator'

words = File.read('source.txt').split

# => ['a', 'ball', 'a', 'ball', 'a', 'red', 'ball']
counts = Hash.new do |hash, key|
  hash[key] = Hash.new(0)
end

words.each_cons(2) do |first, second|
  counts[first][second] += 1
end

# => {'a'    => {'ball' => 2, 'red' => 1},
#     'red' => {'ball' => 1},
#     'ball' => {'a' => 2}}
choices = {}
counts.each do |word, succ|
  choices[word] = succ.inject([]) do |memo, obj|
    item, times = obj
    memo + ([item] * times)
  end
end

# => {'a'    => ['ball', 'ball', 'red'],
#     'red' => ['ball'],
#     'ball' => ['a', 'a']}
victim = words.first

50.times do
  print victim + ' '
  candidates = choices[victim] || [words.first]
  victim = candidates[rand(candidates.length)]
end
What people had four years ago. That's when
an automated script---especially a set of the
programmer's more discerning. In the
Examples This book that your customers (or
someone undoes all of RSpec example for text
into a human ingenuity. So, we're going to refer
to read or missing requirements.
select_all
select_all
                  paste
paste
                  find
find
                  find
find
                  find
find
                  find
edit
                  find
edit
                  find
edit
                  find
save_as
                  find
open
                  find
change_password
                  edit
change_password
                  edit
exit_app
                  save_as
#2
TDD means automation
Mouse hooks
http://cboard.cprogramming.com/
showthread.php?t=66174
require 'rubygems'
require 'win32/api'

module Win32
  @@get_module_handle = API.new 
    'GetModuleHandle', 'L', 'L', 'kernel32'
end
module Win32
  [['SetWindowsHookEx', 'LKLL', 'L'],
   ['UnhookWindowsHookEx', 'L', 'I'],
   ['CallNextHookEx', 'LLLP', 'L'],
   ['GetMessage', 'PLLL', 'I'],
   ['TranslateMessage', 'P', 'I'],
   ['DispatchMessage', 'P', 'L'],
   ['GetCursorPos', 'P', 'I']].each do
      |name, sig, ret|

        var = '@@' + name.snake_case
        api = API.new name, sig, ret, 'user32'
        class_variable_set var, api
  end
end
class String
  def snake_case
    gsub(/([a-z])([A-Z0-9])/, '1_2').downcase
  end
end
module Win32
  WH_MOUSE_LL = 14
  WM_LBUTTONDOWN = 0x201
  WM_LBUTTONUP = 0x202

  class API
    def [](*args)
      call *args
    end
  end
end
class MouseWatcher
  include Win32

  private

  def mouse_hook(code, w, l)
    case w
    when WM_LBUTTONDOWN then @down = true
    when WM_LBUTTONUP then @down = false
    else if @down then
           point = quot;0quot; * 8
           @@get_cursor_pos[point]
           x, y = point.unpack 'LL'
           puts quot;#{x} #{y}quot;
         end
    end

    @@call_next_hook_ex[@hook, code, w, l]
  end
end
class MouseWatcher
  def initialize
    @down = false

    @callback = API::Callback.new 
      'LLP',
      'L',
      &method(:mouse_hook)
  end
end
class MouseWatcher
  def go
    mod = @@get_module_handle[0]
    @hook = @@set_windows_hook_ex[
      WH_MOUSE_LL, @callback, mod, 0]

    msg = quot;0quot; * 28
    while 0 != @@get_message[msg, 0, 0, 0]
      @@translate_message[msg]
      @@dispatch_message[msg]
    end
  rescue Interrupt
    @@unhook_windows_hook_ex[@hook]
    @hook = nil
  end
end
MouseWatcher.new.go




      287   118
      287   118
      287   118
      373   258
      427   306
      427   307
      426   307
      424   307
      ...
Heat maps
http://blog.corunet.com/english/the-definitive-
heatmap
require 'rmagick'
include Magick

canvas = Image.new 640, 480 do
  self.background_color = 'black'
end

finger = Image.new 20, 20 do
  self.background_color = 'black'
end
draw = Draw.new
draw.stroke 'white'
draw.stroke_opacity 0.3
draw.fill 'white'
draw.fill_opacity 0.3
draw.circle 10, 10, 5, 10
draw.draw finger
finger = finger.blur_image

finger = finger.level_channel 
           BlueChannel,
           0,
           QuantumRange / 128

finger = finger.recolor 
           [1,   1,   0,
            0,   0.2, 0,
            0,   0,   0.9]
background = Image.read('window.png').first

background = background.modulate 0.25, 0.25
File.open('mouse.txt') do |f|
  f.each_line do |l|
    x, y = l.split.map {|s| s.to_i}
    background.composite! finger, x, y,
      PlusCompositeOp
  end
end

background.write 'heatmap.png'
Guilt-driven development
http://github.com/undees/yesbut
http://bitbucket.org/undees/yesbut
#3
We’re done talking
about testing
Yes, But
Yes, But

More Related Content

What's hot

Good Evils In Perl
Good Evils In PerlGood Evils In Perl
Good Evils In Perl
Kang-min Liu
 
Perl.Hacks.On.Vim
Perl.Hacks.On.VimPerl.Hacks.On.Vim
Perl.Hacks.On.Vim
Lin Yo-An
 
Cpp11 multithreading and_simd_linux_code
Cpp11 multithreading and_simd_linux_codeCpp11 multithreading and_simd_linux_code
Cpp11 multithreading and_simd_linux_code
Russell Childs
 

What's hot (20)

Descobrindo a linguagem Perl
Descobrindo a linguagem PerlDescobrindo a linguagem Perl
Descobrindo a linguagem Perl
 
Bringing characters to life for immersive storytelling
Bringing characters to life for immersive storytellingBringing characters to life for immersive storytelling
Bringing characters to life for immersive storytelling
 
Good Evils In Perl
Good Evils In PerlGood Evils In Perl
Good Evils In Perl
 
Ruby Intro {spection}
Ruby Intro {spection}Ruby Intro {spection}
Ruby Intro {spection}
 
Real life-coffeescript
Real life-coffeescriptReal life-coffeescript
Real life-coffeescript
 
JavaScript Design Patterns
JavaScript Design PatternsJavaScript Design Patterns
JavaScript Design Patterns
 
Hangman Game Programming in C (coding)
Hangman Game Programming in C (coding)Hangman Game Programming in C (coding)
Hangman Game Programming in C (coding)
 
There and Back Again
There and Back AgainThere and Back Again
There and Back Again
 
Advanced Shell Scripting
Advanced Shell ScriptingAdvanced Shell Scripting
Advanced Shell Scripting
 
Elixir cheatsheet
Elixir cheatsheetElixir cheatsheet
Elixir cheatsheet
 
Communities - Perl edition (RioJS)
Communities - Perl edition (RioJS)Communities - Perl edition (RioJS)
Communities - Perl edition (RioJS)
 
Fancy talk
Fancy talkFancy talk
Fancy talk
 
ATS language overview
ATS language overviewATS language overview
ATS language overview
 
(Parameterized) Roles
(Parameterized) Roles(Parameterized) Roles
(Parameterized) Roles
 
Arduino coding class
Arduino coding classArduino coding class
Arduino coding class
 
Dip Your Toes in the Sea of Security (PHP MiNDS January Meetup 2016)
Dip Your Toes in the Sea of Security (PHP MiNDS January Meetup 2016)Dip Your Toes in the Sea of Security (PHP MiNDS January Meetup 2016)
Dip Your Toes in the Sea of Security (PHP MiNDS January Meetup 2016)
 
Perl.Hacks.On.Vim
Perl.Hacks.On.VimPerl.Hacks.On.Vim
Perl.Hacks.On.Vim
 
Cpp11 multithreading and_simd_linux_code
Cpp11 multithreading and_simd_linux_codeCpp11 multithreading and_simd_linux_code
Cpp11 multithreading and_simd_linux_code
 
JavaScript and the AST
JavaScript and the ASTJavaScript and the AST
JavaScript and the AST
 
Ruby - Uma Introdução
Ruby - Uma IntroduçãoRuby - Uma Introdução
Ruby - Uma Introdução
 

Similar to Yes, But

OWASP PHPIDS talk slides
OWASP PHPIDS talk slidesOWASP PHPIDS talk slides
OWASP PHPIDS talk slides
guestd34230
 
Uses & Abuses of Mocks & Stubs
Uses & Abuses of Mocks & StubsUses & Abuses of Mocks & Stubs
Uses & Abuses of Mocks & Stubs
PatchSpace Ltd
 
Rapid Development with Ruby/JRuby and Rails
Rapid Development with Ruby/JRuby and RailsRapid Development with Ruby/JRuby and Rails
Rapid Development with Ruby/JRuby and Rails
elliando dias
 
Your Library Sucks, and why you should use it.
Your Library Sucks, and why you should use it.Your Library Sucks, and why you should use it.
Your Library Sucks, and why you should use it.
Peter Higgins
 

Similar to Yes, But (20)

Ruby Topic Maps Tutorial (2007-10-10)
Ruby Topic Maps Tutorial (2007-10-10)Ruby Topic Maps Tutorial (2007-10-10)
Ruby Topic Maps Tutorial (2007-10-10)
 
SQL -PHP Tutorial
SQL -PHP TutorialSQL -PHP Tutorial
SQL -PHP Tutorial
 
Little Big Ruby
Little Big RubyLittle Big Ruby
Little Big Ruby
 
OWASP PHPIDS talk slides
OWASP PHPIDS talk slidesOWASP PHPIDS talk slides
OWASP PHPIDS talk slides
 
Questioning the status quo
Questioning the status quoQuestioning the status quo
Questioning the status quo
 
CoffeeScript - A Rubyist's Love Affair
CoffeeScript - A Rubyist's Love AffairCoffeeScript - A Rubyist's Love Affair
CoffeeScript - A Rubyist's Love Affair
 
Uses & Abuses of Mocks & Stubs
Uses & Abuses of Mocks & StubsUses & Abuses of Mocks & Stubs
Uses & Abuses of Mocks & Stubs
 
Reasons To Love Ruby
Reasons To Love RubyReasons To Love Ruby
Reasons To Love Ruby
 
Re-Design with Elixir/OTP
Re-Design with Elixir/OTPRe-Design with Elixir/OTP
Re-Design with Elixir/OTP
 
Rapid Development with Ruby/JRuby and Rails
Rapid Development with Ruby/JRuby and RailsRapid Development with Ruby/JRuby and Rails
Rapid Development with Ruby/JRuby and Rails
 
Rooted 2010 ppp
Rooted 2010 pppRooted 2010 ppp
Rooted 2010 ppp
 
Javascript Best Practices
Javascript Best PracticesJavascript Best Practices
Javascript Best Practices
 
NYU hacknight, april 6, 2016
NYU hacknight, april 6, 2016NYU hacknight, april 6, 2016
NYU hacknight, april 6, 2016
 
A Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source Code
A Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source CodeA Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source Code
A Unicorn Seeking Extraterrestrial Life: Analyzing SETI@home's Source Code
 
Why Windows 8 drivers are buggy
Why Windows 8 drivers are buggyWhy Windows 8 drivers are buggy
Why Windows 8 drivers are buggy
 
Your Library Sucks, and why you should use it.
Your Library Sucks, and why you should use it.Your Library Sucks, and why you should use it.
Your Library Sucks, and why you should use it.
 
2013-06-15 - Software Craftsmanship mit JavaScript
2013-06-15 - Software Craftsmanship mit JavaScript2013-06-15 - Software Craftsmanship mit JavaScript
2013-06-15 - Software Craftsmanship mit JavaScript
 
2013-06-24 - Software Craftsmanship with JavaScript
2013-06-24 - Software Craftsmanship with JavaScript2013-06-24 - Software Craftsmanship with JavaScript
2013-06-24 - Software Craftsmanship with JavaScript
 
Blocks by Lachs Cox
Blocks by Lachs CoxBlocks by Lachs Cox
Blocks by Lachs Cox
 
[FT-7][snowmantw] How to make a new functional language and make the world be...
[FT-7][snowmantw] How to make a new functional language and make the world be...[FT-7][snowmantw] How to make a new functional language and make the world be...
[FT-7][snowmantw] How to make a new functional language and make the world be...
 

More from Erin Dees

Write Your Own JVM Compiler
Write Your Own JVM CompilerWrite Your Own JVM Compiler
Write Your Own JVM Compiler
Erin Dees
 

More from Erin Dees (10)

Your Own Metric System
Your Own Metric SystemYour Own Metric System
Your Own Metric System
 
Thnad's Revenge
Thnad's RevengeThnad's Revenge
Thnad's Revenge
 
Logic Lessons That Last Generations
Logic Lessons That Last GenerationsLogic Lessons That Last Generations
Logic Lessons That Last Generations
 
JRuby, Not Just For Hard-Headed Pragmatists Anymore
JRuby, Not Just For Hard-Headed Pragmatists AnymoreJRuby, Not Just For Hard-Headed Pragmatists Anymore
JRuby, Not Just For Hard-Headed Pragmatists Anymore
 
Playfulness at Work
Playfulness at WorkPlayfulness at Work
Playfulness at Work
 
Write Your Own JVM Compiler
Write Your Own JVM CompilerWrite Your Own JVM Compiler
Write Your Own JVM Compiler
 
How 5 people with 4 day jobs in 3 time zones enjoyed 2 years writing 1 book
How 5 people with 4 day jobs in 3 time zones enjoyed 2 years writing 1 bookHow 5 people with 4 day jobs in 3 time zones enjoyed 2 years writing 1 book
How 5 people with 4 day jobs in 3 time zones enjoyed 2 years writing 1 book
 
How 5 people with 4 day jobs in 3 time zones enjoyed 2 years writing 1 book
How 5 people with 4 day jobs in 3 time zones enjoyed 2 years writing 1 bookHow 5 people with 4 day jobs in 3 time zones enjoyed 2 years writing 1 book
How 5 people with 4 day jobs in 3 time zones enjoyed 2 years writing 1 book
 
A jar-nORM-ous Task
A jar-nORM-ous TaskA jar-nORM-ous Task
A jar-nORM-ous Task
 
Cucumber meets iPhone
Cucumber meets iPhoneCucumber meets iPhone
Cucumber meets iPhone
 

Recently uploaded

Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 

Recently uploaded (20)

Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKSpring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
Cyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdfCyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdf
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 

Yes, But

Editor's Notes

  1. The first leg of the epic, hopefully transcontinental book tour kicked off in my own backyard, at the technical annex of the huge Powell’s Books.
  2. Just in case you were at Ignite Portland that night, here’s a recreation of my talk.
  3. As the name implies, the book will teach you how to introduce automation into your user interface testing efforts, without making a bunch of false promises about its capabilities.
  4. I was going to give the presentation this provocative title, as a signal that I’d be revisiting various points of view in the book and looking at them from a different angle.
  5. But this title conveys the idea much more succinctly. If I can convey an idea from the book, and then talk about the edge cases where it doesn’t apply, then this talk will have a little something both for people who have read the book and those who haven’t.
  6. So, let’s get started. One of my big motivations for writing the book was my dissatisfaction with testing tools that are based on recording a bunch of mouse clicks and then replaying them.
  7. Such tools often generate unreadable code like this. How do you even know where you’re supposed to add the tests?
  8. The problem is that many of these tools capture the wrong things. They dutifully record exact screen coordinates, instead of what the user was trying to do (e.g., delete a document, zap an alien, etc.).
  9. It’s impossible to capture the user’s intent when all we have are keyboard and mouse actions, right? That’s the prevailing wisdom. But then I saw a talk by Dr. Atif Memon, who pretty much knocked all of us out of our chairs.
  10. Instead of capturing raw mouse actions, Dr. Memon proposes to capture relationships between actions—specifically, the fact that one behavior, such as saving a document, frequently follows another.
  11. From a directed graph of actions following actions, Dr. Memon’s team used a random walk to generate test cases. He didn’t say how they chose which nodes to traverse, but I suspect they used a dash of probabilistic techniques, such as the Markov Chains used for Garkov here.
  12. Garkov, by the way, uses a corpus of Garfield captions to generate random, surreal dialogue for the comic strip. Here’s another one from Josh Millard’s site; I couldn’t resist.
  13. Dr. Memon’s technique is a work in progress. But that doesn’t mean you can’t apply probability to your own test cases on a much smaller scale. The technique you’re about to see was inspired by Sammy Larbi’s article above, but with completely different Ruby code.
  14. Let’s say you want to generate random sequences of words, based on the way they occur naturally in this text. For example, the word “red” will always be followed by “ball,” but the word “a” could have “ball” or “red” after it.
  15. First, split the document into words.
  16. Next, build a table linking each word to the list of all words that directly follow it, and how frequently they follow it. For example, you can see that “a” has been followed by two words: “ball” twice, and “red” once.
  17. After all the counting is done, build a list of possible successors for each word. Use repetition to signal that one word has followed another one multiple times. That way, when you pick a random word from the list, you’re more likely to get a common follower than a rare one.
  18. Now you can generate as many random words as you like. Simply grab a word, print it, and then choose a random item from the list of words that are “allowed” to follow it. Repeat until you’ve generated a sufficiently absurd document.
  19. Here’s what the technique looks like when you apply it to the first chapter of my book. There are lots of ways to modify this technique, like looking at sequences longer than just pairs, or by considering letters instead of words.
  20. You can also apply it to a test log instead of a sentence. Here’s a real sequence of actions I captured from my computer, and a brand new test script generated from them. As you can see, you really need a longer capture log before these scripts get interesting.
  21. Okay, on to viewpoint #2. In the book, I talk a little bit about test-driven development and behavior-driven development in the context of automation. But there are plenty of times when completely manual tests give you information that you use to shape a product.
  22. For example, when you turn off this touch-screen instrument and shine a light at the right angle...
  23. ...you can see fingerprints on the most frequently-used parts of the interface. This is a developer’s machine, and he was comfortable using the on-screen data entry “knob” in the corner. But the machines we showed to customers came back with almost no prints on it.
  24. After getting a brief facelift, the data entry control received a warmer reception from our users’ fingertips.
  25. Even though this test started as a lo-fi, non-automated, analog kind of technique, there’s no reason we can’t go back after the fact and make an automated version. The forum linked above gives a quick intro to capturing mouse and keyboard events using C on Windows platforms.
  26. Of course, this is a talk on Ruby, so let’s apply the techniques in Ruby using the win32 gem. First, there are a handful of Windows functions to define. We could define them one by one, like this.
  27. But the book gives a technique (you can download the source for free) for automatically assigning Ruby names to the Windows functions.
  28. The technique uses this method of turning Windows-style “CamelCase” names into Ruby-style “snake_case” ones.
  29. Finally, you’ll need to define a few common Windows constants, and a shorthand for invoking the C functions from Ruby.
  30. Here’s the meat of the mouse hook. Windows will call into this Ruby function when there’s mouse activity, passing in enough information to reconstruct exactly what happened. In this case, you’re just going to record the screen coordinates whenever the user drags his finger/mouse.
  31. Here’s the bit of glue that makes the callback magic happen.
  32. And finally, here’s the main loop. After you assign the mouse hook, you just sit in a message loop until you’ve logged all the data you want.
  33. The output is a series of space-delimited x/y pairs, one per line. Each point represents one place where the user has dragged the mouse.
  34. What can we do with that list of coordinates? How about a heat map? The article linked above describes a very detailed technique; I’m going to give a much lighter one that fits the broad scope of this talk.
  35. You’ll need ImageMagick and its Ruby wrapper, RMagick. Start with a screen-sized empty black background, and a small tile to represent the “finger” smudging the screen.
  36. Draw a semi-transparent white circle into the finger tile to represent the fingertip.
  37. Now, bias the low end of the finger towardd blue, and the high end toward pink. There are much cleverer techniques that can get you a rainbow of hot and cool colors, but this simple trick will work well enough for now.
  38. Now, load the screenshot into the picture and dim it quite a bit.
  39. Then for each place the user clicked or dragged, add the fingertip image in. The effect is cumulative; frequently-touched parts of the screen will be brighter.
  40. Here’s what the result looks like after a very short interaction.
  41. And with a pang of guilt for throwing this stuff together practically on the eve of the talk, here are links to all the code you’ve seen.
  42. The book purposefully skirts around the subject of testing philosophy, since that subject is extremely well covered. But I don’t want to leave the impression that the topic is completely exhausted.
  43. Writers, coders, and testers are still challenging old notions and documenting new techniques. So please take tonight’s talk as a call to tinker, explore, and flip old approaches onto their heads.