スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

JRubyによるSikuli操作2

JRubyによるSikuli操作1 で作成したサンプルをSelenium WebDriverで提案されているPageObject的に作成し直したサンプル。Specで簡単にテストを追加できるので、結構いい感じ。

●calculator.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
STDOUT.sync = true

require 'java'
$CLASSPATH << "/Users/XXX/develop/SikuliX"
require "sikulixapi.jar"

java_import org.sikuli.script.App
java_import org.sikuli.script.Screen
java_import org.sikuli.script.Region
java_import org.sikuli.script.Sikulix
java_import org.sikuli.script.Key
java_import org.sikuli.script.KeyModifier
java_import org.sikuli.basics.Settings

# for Java clipboard
java_import java.awt.Toolkit
java_import java.awt.datatransfer.Clipboard
java_import java.awt.datatransfer.DataFlavor
java_import java.awt.datatransfer.StringSelection

class Calculator
def initialize()
# ready for clipboard
toolkit = Toolkit.getDefaultToolkit()
@clipboard = toolkit.getSystemClipboard()

Settings.MoveMouseDelay = 0 # 0[sec]

@app = App.open("calculator")
@app.focus()
@scn = Screen.new
@scn.wait("calculator.png", 5)
end

def finalize
App.close("calculator")
end

def copy(contents)
@clipboard.setContents(StringSelection.new(contents), nil)
end

def paste()
#`pbpaste` # just for Mac
contents = @clipboard.getContents(nil)
contents.getTransferData(DataFlavor.stringFlavor)
end

def copy()
@scn.type('c', KeyModifier::CMD)
end

def get_result()
copy()
paste()
end

def click(key)
@scn.click(key+'.png')
end

def clear()
if @scn.exists("C.png")
click("C")
else
click("AC")
end
end
end


●calc_spec.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
STDOUT.sync = true
require "rspec"
include RSpec::Expectations

require_relative 'calculator' # テストターゲット

describe "計算機" do
before(:all) do
@calc = Calculator.new
end

after(:all) do
@calc.finalize
end

it "test 1 + 2 = 3" do
@calc.clear()
@calc.click("1")
@calc.click("+")
@calc.click("2")
@calc.click("=")
expect(@calc.get_result()).to eq "3"
end

it "test 2 - 3 = -1" do
@calc.clear()
@calc.click("2")
@calc.click("-")
@calc.click("3")
@calc.click("=")
expect(@calc.get_result()).to eq "-1"
end

it "test 2 x 3 = 6" do
@calc.clear()
@calc.click("2")
@calc.click("x")
@calc.click("3")
@calc.click("=")
expect(@calc.get_result()).to eq "6"
end

it "test 1 / 2 = 0.5" do
@calc.clear()
@calc.click("1")
@calc.click("d") # d.png -> /
@calc.click("2")
@calc.click("=")
expect(@calc.get_result()).to eq "0.5"
end

it "test 1 / 0 = 数値ではありません" do
@calc.clear()
@calc.click("1")
@calc.click("d") # d.png -> /
@calc.click("0")
@calc.click("=")
expect(@calc.get_result()).to eq "数値ではありません"
end
end
                    



スポンサーサイト

JRubyによるSikuli操作1

JRuby/RSpecからSikuliを使ったテストプログラムのサンプル。計算機の結果はJavaのクリップボードを使って取得する様にしてみた。JRubyからSikuliとJavaの両方が使える様になったので、とっても便利。

●環境
・MAC:OS X El Capitan
・Sikuli-1.1.0
・JRuby:jruby-9.0.0.0.pre1

●参考にさせていただいたURL
画像認識でアプリケーション操作の自動化を実現!Sikuliがあまりに革命的で興奮した
How-To: Sikuli and Robot Framework Integration
masuoのブログ:Sikuliに関する日本語情報がいっぱい

●calc_spec.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
STDOUT.sync = true
require "rspec"
include RSpec::Expectations

require 'java'
$CLASSPATH << "/Users/XXX/develop/SikuliX"
require "sikulixapi.jar"

java_import org.sikuli.script.App
java_import org.sikuli.script.Screen
java_import org.sikuli.script.Region
java_import org.sikuli.script.Sikulix
java_import org.sikuli.script.Key
java_import org.sikuli.script.KeyModifier
java_import org.sikuli.basics.Settings

# for clipboard
java_import java.awt.Toolkit
java_import java.awt.datatransfer.Clipboard
java_import java.awt.datatransfer.DataFlavor
java_import java.awt.datatransfer.StringSelection

describe "計算機" do
def copy(contents)
@clipboard.setContents(StringSelection.new(contents), nil)
end

def paste()
#`pbpaste` # just for Mac
contents = @clipboard.getContents(nil)
contents.getTransferData(DataFlavor.stringFlavor)
end

before(:all) do
@app = App.open("calculator")
@app.focus()
@scn = Screen.new

Settings.MoveMouseDelay = 0 # 0.0[sec]

# ready for clipboard
toolkit = Toolkit.getDefaultToolkit()
@clipboard = toolkit.getSystemClipboard()
end

after(:all) do
App.close("calculator")
end

it "test 1 + 2 = 3" do
@scn.wait("calculator.png", 5)
if @scn.exists("C.png")
@scn.click("C.png")
else
@scn.click("AC.png")
end
@scn.click("1.png")
@scn.click("+.png")
@scn.click("2.png")
@scn.click("=.png")
@scn.type('c', KeyModifier::CMD)
expect(paste()).to eq "3"
end

it "test 2 x 3 = 6" do
if @scn.exists("C.png")
@scn.click("C.png")
else
@scn.click("AC.png")
end
@scn.click("2.png")
@scn.click("x.png")
@scn.click("3.png")
@scn.click("=.png")
@scn.type('c', KeyModifier::CMD)
expect(paste()).to eq "6"
end
end

Sikuliによる自動テスト

Sikuliによる自動テストのサンプル。スクリプト言語としてはRuby(JRuby)で記述。Pythonで提供されているAPIとは若干異なるところがあるみたい(バグでは?)

●環境
・MAC:OS X El Capitan
・Sikuli-1.1.0

calc.rb
# -*- coding: utf-8 -*-

puts("計算機アプリ")
a = App.open("calculator")
wait("1450179771753.png")
click("1450179797167.png")
click("1450179815461.png")
click("1450179797167.png")
click("1450179848496.png")
popup("Rubyによるスクリプト実行")
#a.close() # something wrong!!
App.close("calculator")

sikuli_calc.png

●参考にさせて頂いた書籍:Sikuli実践ガイド

Selenium WebDriverによるRubyテストスクリプト例

Selenium WebDriverによるRubyテストスクリプトの作成例。

●環境
・MacBook Air: OS X El Capitan
・Ruby: 2.0.0
・対応ブラウザ:Firefox, Chrome, Safari

●特徴
・PageObjectパターン(もどき)を利用し保守性を向上
・テストが失敗した時にスクリーンショットを保存
・RSpecによる自動テスト

●google.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
STDOUT.sync = true

require 'selenium-webdriver'

class MyWebDriver
attr_accessor :driver

def initialize(timeout, *browser)
@driver = Selenium::WebDriver.for *browser
@driver.manage.timeouts.implicit_wait = timeout
end

def quit()
@driver.quit
end

def fail(file_name)
@driver.save_screenshot(file_name)
end
end

class BasePage
def initialize(driver)
@driver = driver
end

def title
@driver.title
end

def current_url
@driver.url
end

def page_source
@driver.page_source
end

def verify_open(title)
if @driver.title.include?(title) == false
raise "fail to open '#{title}'" # 例外の送信
end
end
end

class GoogleSearchResultPage < BasePage
def initialize(driver)
super(driver)
wait = Selenium::WebDriver::Wait.new(:timeout => 10) # second
wait.until { @driver.find_element(:id => "search").displayed? }

# NOTE: 検索結果でdivは4階層か3階層で動的に変化
@ranking_data = @driver.find_elements(:xpath, "//div/div/div/h3/a")

# @ranking_data.each do |site|
# puts site.attribute("href")
# end

verify_open("Google") # 日本語:"Google 検索", 英語:"Google Search"
end

def select(index)
@driver.get @ranking_data[index].attribute("href")
end
end

class GoogleSearchPage < BasePage
def initialize(driver)
super(driver)
@base_url = "https://www.google.co.jp/"
@driver.get(@base_url + "/")
@lst_ib = @driver.find_element(:id, "lst-ib")
verify_open("Google")
end

def search(keyword)
@lst_ib.clear
@lst_ib.send_keys keyword + "\n" # 補完が効いているので改行を入力
@lst_ib.submit

return GoogleSearchResultPage.new(@driver)
end
end


●google_spec.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
STDOUT.sync = true

require 'selenium-webdriver'
require_relative 'google'

describe "Selenium" do
context "Selenium WebdriverでFirefoxテスト" do
before do
@mydriver = MyWebDriver.new(30, :firefox)
end

it "検索テスト" do
begin
page = GoogleSearchPage.new(@mydriver.driver)
expect(page.title).to eq "Google"
result = page.search("selenium")
expect(result.title).to include "Google 検索"
result.select(0) # 1番目の検索結果を選択
rescue => e
p e
# puts e.backtrace
# スクリーンショット保存
@mydriver.fail("#{File.basename(__FILE__)}_#{__LINE__}.png")
raise e # 例外の再送信
end

end

after do
@mydriver.quit
end
end

context "Selenium WebdriverでChromeテスト" do
before do
@mydriver = MyWebDriver.new(30, :chrome)
end

it "検索テスト" do
begin
page = GoogleSearchPage.new(@mydriver.driver)
expect(page.title).to eq "Google"
result = page.search("selenium")
expect(result.title).to include "Google 検索"
result.select(1) # 2番目の検索結果を選択
rescue => e
p e
# puts e.backtrace
# スクリーンショット保存
@mydriver.fail("#{File.basename(__FILE__)}_#{__LINE__}.png")
raise e # 例外の再送信
end

end

after do
@mydriver.quit
end
end

context "Selenium WebdriverでSafariテスト" do
before do
@mydriver = MyWebDriver.new(30, :safari)
end

it "検索テスト" do
begin
page = GoogleSearchPage.new(@mydriver.driver)
expect(page.title).to eq "Google"
result = page.search("selenium")
expect(result.title).to include "Google Search" # なぜかtitleは英語
result.select(2) # 3番目の検索結果を選択
rescue => e
p e
# puts e.backtrace
# スクリーンショット保存
@mydriver.fail("#{File.basename(__FILE__)}_#{__LINE__}.png")
raise e # 例外の再送信
end

end

after do
@mydriver.quit
end
end

def alert_present?()
@driver..switch_to.alert
true
rescue Selenium::WebDriver::Error::NoAlertPresentError
false
end

def verify(&blk)
yield
rescue ExpectationNotMetError => ex
@verification_errors << ex
end

def close_alert_and_get_its_text(how, what)
alert = @driver.switch_to().alert()
alert_text = alert.text
if (@accept_next_alert) then
alert.accept()
else
alert.dismiss()
end
alert_text
ensure
@accept_next_alert = true
end
end


●実行結果
$ rspec -fd google_spec.rb

Selenium
Selenium WebdriverでFirefoxテスト
検索テスト
Selenium WebdriverでChromeテスト
検索テスト
Selenium WebdriverでSafariテスト
検索テスト

Finished in 32.98 seconds (files took 0.34337 seconds to load)
3 examples, 0 failures

RubyでWin32OLEを使ったExcelサンプルプログラム

 別に目新しいものは何もないが、RubyでExcelを使うために自分用作業メモで、Windows環境でのWin32OLEを使ったExcelアクセスサンプルプログラム(Qiitaにも投稿したが、こちらはブログの広告消すのが主な目的)。
 以前、Pythonで PythonでExcel を作成したが、基本は同じ。RubyだからPythonに比べてもっと情報あるかと思ったが、情報が結構散在している感じがする。やっぱ、Excel使う人はPython/Rubyではなく、VBAを使うのが一般的??

●参考にさせて頂いたURL
RubyからExcelを操作する方法について | Futurismo
Rubyist Magazine - Win32OLE 活用法 【第 2 回】 Excel
win32ole で Excel を使う(4)
Ruby から Excel を操作する方法
 九九のサンプルはこちらを参考にさせて頂いています

●サンプルプログラム:excel_test.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
STDOUT.sync = true

require 'win32ole'

# Excel VBA定数のロード
module Excel; end

def init_excel()
# Excelオブジェクト生成
excel = WIN32OLE.new('Excel.Application')
excel.visible = true
# 上書きメッセージを抑制
excel.displayAlerts = false

WIN32OLE.const_load(excel, Excel)

return excel
end

def create_excel(excel, file)
# 新規ブックを作成
workbook = excel.workbooks.add

# 先頭シートを選択
sheet = workbook.sheets[1]

# 九九の表を作成
(1..9).each do |i|
sheet.rows[1].columns[i + 1] = i
sheet.rows[i + 1].columns[1] = i
end
sheet.range('B2:J10').value = '=$A2*B$1'

# ボーダーライン
sheet.range('A1:J10').borders.lineStyle = Excel::XlContinuous

# 表のヘッダー
range = sheet.range('A1:A10,B1:J1')
# 背景色
range.interior.themeColor = Excel::XlThemeColorAccent1
# フォント
range.font.themeColor = Excel::XlThemeColorDark1
range.font.bold = true

# 列の幅
sheet.columns('A:J').columnWidth = 6

# 保存
workbook.saveAs(file)

# ファイルを閉じる
workbook.close
end

def read_excel(excel, file, sheet_num = 1)
book = excel.Workbooks.Open(file)
sheet = book.Worksheets(sheet_num)

# 列ごとに処理
sheet.UsedRange.Rows.each do |row|
# セルごとに処理
row.Columns.each do |cell|
puts cell.value
end
end
end

def main()
# OLE32用FileSystemObject生成
fso = WIN32OLE.new('Scripting.FileSystemObject')
file = fso.GetAbsolutePathName('./sample.xlsx')

excel = init_excel()

create_excel(excel, file)
read_excel(excel, file)

excel.quit()
end

main()
プロフィール

Author:Zaike Yuki
オブジェクト指向、C++/Java、Python、Eclipse、Android、等に興味を持つソフトウェアエンジニア

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。