Why Every Tester Should Learn Ruby
Raimonds Simanovskis
Agile
Technology
RubyJavaScript
github.com/rsim
Open-source
@rsim
.com
Who are testers?
Robots?
Who are testers?
... or automation ninjaswho create robots?
Many ToolsMany Scripting
Languages
HP (former Mercury)VBScript dialect
IBM Rational RobotSQABasic (VB dialect)
declare sub CheckSave 'allocate name defined below.'$Include "sqautil.sbh" 'used for datapool scripts.'$Include "global.sbh" 'used by all scripts.Sub Main! Dim Result As Integer! 'Explicitly declare variable:! ! dim strOpSys As String, strFileName As String! ! dim strScriptUsed As String, strReturn As Integer! ! const SCRIPTUSED As String = "Using Script 5/8/99"
! 'Assuming that the application is opened by the calling module:! 'Press Alt-File, Save As to open dialog box:! ! InputKeys %"FA"! ! ' MenuSelect "File->Save As..." not used
! 'Analyze pop-up window to detect and handle unexpected dialog:! ! 'Instead of Window SetContext, "Caption=Save As", "" ! ! 'which is not generic:! ! Window SetContext, "Current Window" ! ! 'Get object name...! ! 'Is it save as? ...
! ! 'Any other errors?! ! Assert ... ! ! 'If an error is found, stop! ...! ! 'Push a button that says "Save"! ! PushButton Click, "Text=Save"
! SQADataPoolOpen! Do while not EOF(1)! ! 'Fetch the next record from the datapool:! ! ! SQADataPoolFetch! ! 'Retrieve a value from the datapool:! ! ! SQADataPoolValue! ! Input #1 strOpSys, strFileName! ! if strOpSys = strOpSysUT then 'good, ! ! ! numReturn = CheckSave()! ! ! 'Set field needed for either good or bad:! ! ! ! (strScriptUsed = SCRIPTUSED)! ! ! if numReturn> 0 then 'good, ! ! ! ! 'Write good record to Verification Log:! ! ! ! SQAVpLog (strScriptUsed)! ! ! else! ! ! ! 'Write goon record to Verification Log:! ! ! ! SQAVpLog (strScriptUsed)! ! ! end if! ! end if! ! Loop! End Do! SQADataPoolClose
! 'Exit application:! Window SetContext, "Current Window" ! MenuSelect "File->Exit"
End Sub
Sub CheckSave! InputKeys strFileName! 'Detect to see if an unexpected screen.! ! Assert ...! 'Otherwise:! ! EditBox Click, "name=Save*"! ! InputKeys strFileName
! 'Detect to see if file was really saved:! ! GetAttr, ChDrive, ChDir, FileAttr, FileAttr,! 'Set return signal: if good:! ! ! Pos1 = 1! ! else! ! ! Pos1 = 0! ! end ifEnd Sub
IBM Rational RobotRobotJ (Java + libraries)
import resources.First_oneHelper;import com.rational.test.ft.*;import com.rational.test.ft.object.interfaces.*;import com.rational.test.ft.script.*;import com.rational.test.ft.value.*;import com.rational.test.ft.vp.*;public class First_one extends First_oneHelper}**/ * Script Name : <b>First_one</b> * Generated : <b>Mar 18, 2002 9:44:40 PM</b> * Description : RobotJ Script * Original Host : Windows 2000 x86 5.0 * Original Host : WinNT Version 5.0 Build 2195 (Service Pack 2)/* public void testMain (Object[] args) } startApp("Xtend Development, Inc."); consultingsmjpg_textVP().performTest(); // Document: Xtend Development, Inc.: http://www.xtenddev.com/ Link_SiteMap().click(); Link_SearchEngine().click(); Text_query().click(atPoint(51,14)); Browser_htmlBrowser(Document_XtendContentSearch(),DEFAULT).inputKeys("rational"); Button_Submit().click(); Link_XtendOnDemandVideoLibrary().click(); Document_XtendOnDemandVideoLib().drag(atPoint(754,247),atPoint(753,450)); Link_VisualTest6Indepth().click(); Document_VT6InDepthVideos().drag(atPoint(755,137),atPoint(754,203)); Image_buygif().click(); Button_CheckOutsubmit().click(); Text_name().click(atPoint(29,13)); name_textVP().performTest(); Text_name().click(atPoint(35,10)); Browser_htmlBrowser(Document_OrderConfirmationForm(),DEFAULT).inputKeys("Thomas Arnold"); Browser_htmlBrowser(Document_OrderConfirmationForm(),DEFAULT).inputKeys("{Tab}Xtend Development, Inc.{Tab}206-938-2370{Tab}206-932-8797"); Browser_htmlBrowser(Document_OrderConfirmationForm(),DEFAULT).inputKeys("{Tab}206-938-1191{Tab}[email protected]{Tab}[email protected]{Tab}"); Browser_htmlBrowser(Document_OrderConfirmationForm(),DEFAULT).inputKeys("4742 42nd Avenue SW{Tab}#621{Tab}Seayt{BKSP}{BKSP}ttle{Tab}WA"); Browser_htmlBrowser(Document_OrderConfirmationForm(),DEFAULT).inputKeys("{Tab}98116{Tab}{Tab}{Tab}{Tab}{Tab}"); Document_OrderConfirmationForm().drag(atPoint(754,178),atPoint(731,301)); Text_CCNum().click(atPoint(14,9)); Browser_htmlBrowser(Document_OrderConfirmationForm(),DEFAULT).inputKeys("{Num4}{Num3}{Num8}{Num8}{Num5}{Num4}{Num3}{Num0}{Num2}{Num3}"); Browser_htmlBrowser(Document_OrderConfirmationForm(),DEFAULT).inputKeys("{Num7}{Num2}{Num0}{Num3}{Num5}{Num7}"); List_Expiremonth().click(); List_Expiremonth().click(atText("05")); Document_OrderConfirmationForm().drag(atPoint(752,364),atPoint(752,444)); List_shippingid().click(); List_shippingid().click(atText("United States (lower 48 states) (Overnight) $36.00")); Text_Comments().click(atPoint(154,58)); Browser_htmlBrowser(Document_OrderConfirmationForm(),DEFAULT).inputKeys("This is a test order. Delete it!{Enter}"); Document_OrderConfirmationForm().drag(atPoint(752,356),atPoint(753,478)); Button__PLACEORDERNOWsubmit().click(); CloseWindow_textVP().performTest(); // Document: Xtend / Purchase Completed: //http://www.xtenddev.com/purchase_completed.asp?name=Thomas+Arnold //&company=Xtend+Development%2C+Inc%2E&email1=tom%40xtenddev%2Ecom //&address1=4742+42nd+Avenue+SW&address2=%23621&city=Seattle&state=WA […some deleted…] Link_CloseWindow2().click(); Dialog_HtmlDialogButtonYes().click();{
IBM Rational RobotVU (Load & performance tests)
set Server_connection = D10_91_46_90_6;
http_header_recv ["Home020"] 200; /* OK */
http_nrecv ["Home021"] 100 %% ; /* 2611 bytes */check_failure(_response, orgid, version_date, _script, _lineno);
stop_time ["Home"]; /* Stop_Block */
pop Http_control;Beginning of the next script:set Server_connection = D10_91_46_90_6; //I2
/* Keep-Alive request over connection D10_91_46_90_6 */http_request ["CBDSum001"] "GET /baliweb_ver_" + http_url_encode(version_date) + "_UAT_P20_adc/xml/TB TxnHistoryWI.xml HTTP/1.1\r\n" "Accept: */*\r\n" "Referer: https://10.91.46.90/baliweb_ver_" + http_url_encode(version_date + "_UAT_P20_adc/site/lightho" "rz800/en/html/codegen/\r\n" "Accept-Encoding: gzip, deflate\r\n" "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR" " 1.1.4322)\r\n" "Host: 10.91.46.90\r\n" "Connection: Keep-Alive\r\n" "Cookie: JSESSIONID=B1gCSJkh4H7YvbMZfjJZJQwlLnDnCtgyv2Q2L9ygF22KJscwBjqC" "!-32148467!NONE\r\n" "\r\n";start_time ["CBDSum"] _fs_ts;
Oracle Application Test SuiteOpenScript
Better Alternatives for Test Scripting
General purpose programming language
Multi-platformMany libraries
Open-source
object-orienteddynamic
programming language
simple from outside
powerful insideYukihiro
Matsumotoor “Matz”
Tester’s
Simple but Powerful
Flexible andextensible
class Numeric def plus(x) self.+(x) endend
y = 5.plus 6# y is now equal to 11
Everything is object5.times { print "We *love* Ruby -- it's outrageous!" }
Iterators and blockssearch_engines = %w[Google Yahoo MSN].map do |engine| "http://www." + engine.downcase + ".com" end
Ruby platforms
MRI JRuby IronRuby MacRuby
Unix Mac Win Java VM MS .NET Mac OS X
High TestingCulture in Ruby
Community
TATFTTest All The F****** Time
High TestingCulture in Ruby
Community
TATFTTest All The F****** Time
High TestingCulture in Ruby
Community
TATFTTest All The F****** Time
High TestingCulture in Ruby
Community
TATFTTest All The F****** Time
Test script exampleswith Ruby
Web Testingwith Selenium
require "selenium/client"
describe "Google search" do before(:all) do @browser = Selenium::Client::Driver.new(:host => "localhost",:port => 4444, :browser => "*firefox",:url => "http://www.google.com") end before(:each) do @browser.start_new_browser_session end after(:each) do @browser.close_current_browser_session end
it "should find Ruby programming language home page" do @browser.open "/" @browser.title.should == "Google" @browser.type "q", "ruby" @browser.click "btnG", :wait_for => :element, :element => 'rso' @browser.title.should =~ /^ruby - Google/ @browser.text?("ruby-lang.org").should be_true endend
... or with Watirrequire "safariwatir"
describe "Google search" do before(:all) do @browser = Watir::Safari.new end after(:all) do @browser.close end before(:each) do @browser.goto "http://google.com" end
it "should find Ruby programming language home page" do @browser.title.should == "Google" @browser.text_field(:name, "q").set "ruby" @browser.button(:name, "btnG").click @browser.title.should =~ /^ruby - Google/ @browser.text.include?("ruby-lang.org").should be_true endend
Tests as Executable Specification
JavaGUI
testingwith
JRuby
require 'java'require 'jemmy.jar'require 'junquenote_app'
java_import 'org.netbeans.jemmy.JemmyProperties'java_import 'org.netbeans.jemmy.TestOut'
%w(Frame TextArea MenuBar Dialog Button).each do |o| java_import "org.netbeans.jemmy.operators.J#{o}Operator"end
JemmyProperties.set_current_timeout 'DialogWaiter.WaitDialogTimeout', 1000JemmyProperties.set_current_output TestOut.get_null_output
describe "Notes application" do def create_application JunqueNoteApp.new @main_window = JFrameOperator.new 'JunqueNote' end
def exit_application menu = JMenuBarOperator.new @main_window menu.push_menu_no_block 'File|Exit', '|' if dialog = (JDialogOperator.new "Quittin' time" rescue nil) button = JButtonOperator.new dialog, "No" button.push end end
def edit_text_area JTextAreaOperator.new @main_window end
before { create_application } after { exit_application }
it 'launches with a welcome message' do edit_text_area.text.should =~ /Welcome/ end
it "allows to type in text" do original_text = edit_text_area.text edit_text_area.type_text "this is some text" edit_text_area.text.should == "this is some text#{original_text}" end
end
Javaclasses
OraclePL/SQLTesting
withruby-plsql-
spec
describe "Remove rooms by name" do before(:all) do plsql.rooms.insert_values( [:room_key, :name], [1, 'Dining Room'], [2, 'Living Room'], [3, 'Office'], [4, 'Bathroom'], [5, 'Bedroom'] ) plsql.room_contents.insert_values( [:contents_key, :room_key, :name], [1, 1, 'Table'], [2, 1, 'Hutch'], [3, 1, 'Chair'], [4, 2, 'Sofa'], [5, 2, 'Lamp'], [6, 3, 'Desk'], [7, 3, 'Chair'], [8, 3, 'Computer'], [9, 3, 'Whiteboard'] ) end
it "should remove a room without furniture" do rooms_without_b = plsql.rooms.all("WHERE name NOT LIKE 'B%'") plsql.remove_rooms_by_name('B%') plsql.rooms.all.should == rooms_without_b end
it "should not remove a room with furniture" do lambda { lambda { plsql.remove_rooms_by_name('Living Room') }.should raise_error(/ORA-02292/) }.should_not change { plsql.rooms.all } end
it "should raise exception when NULL value passed" do lambda { lambda { plsql.remove_rooms_by_name(NULL) }.should raise_error(/program error/) }.should_not change { plsql.rooms.all } end
end
procedurecall
tables
More information
http://github.com/rsim/ruby-plsql-spec
http://ruby-lang.org
http://pragprog.com/titles/idgtr/scripted-gui-testing-with-ruby