Sikuli Selenium Robotframework 集成

来源:互联网 发布:编程:字符串压缩 编辑:程序博客网 时间:2024/05/16 07:54

Sikuli Selenium Robotfraamework 集成

原文:http://www.8bitavenue.com/2012/04/sikuli-selenium-robot-framework-integration/

1、需要的所有安装包

sikuli

selenium(webdriver)

RobotFramework

python(2.7.2版本)

Java Run Time Installation

Jython

Easy Install setuptools-0.6c11.win32-py2.7.exe

pip 下载后放入C:\Python\Scripts 进入cmd 输入

    easy_install pip    python ez_setup.py

2、设置环境变量

C:\python27C:\Python27\ScriptsC:\jython2.5.2\binC:\Program Files (x86)\Java\jre6\bin

3、安装

easy_install robotframeworkeasy_install wxPythoneasy_install robotframework-rideeasy_install robotframework-selenium2library

4、Sikuli selenium和RobotFrameWork开始工作了

按照以下的步骤配置,就可以在RobotFramework中同时应用sikuli和selenium一直写case了。其中seleniumlibrary运行在python环境下,sikuli需要Jython支持才能通过python解析。通过RPC-xml服务使本地python和远端机器运行Jython来实现本地selenium和远端机器的sikuli共同工作。

  1. 创建 [C:\robot] [C:\robot\data] [C:\robot\libs] [C:\robot\suites]
  2. 下载Python远端服务放到[C:\robot\libs]下robotremoteserver.py googlecode有可能已经被墙了,下面代码可以自行保存成robotremoteserver.py

    #  Copyright 2008-2014 Nokia Solutions and Networks##  Licensed under the Apache License, Version 2.0 (the "License");#  you may not use this file except in compliance with the License.#  You may obtain a copy of the License at##  http://www.apache.org/licenses/LICENSE-2.0##  Unless required by applicable law or agreed to in writing, software#  distributed under the License is distributed on an "AS IS" BASIS,#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.#  See the License for the specific language governing permissions and#  limitations under the License.__version__ = 'devel'import errnoimport reimport selectimport sysimport inspectimport tracebackfrom StringIO import StringIOfrom SimpleXMLRPCServer import SimpleXMLRPCServerfrom xmlrpclib import Binarytry:import signalexcept ImportError:signal = Nonetry:from collections import Mappingexcept ImportError:Mapping = dictBINARY = re.compile('[\x00-\x08\x0B\x0C\x0E-\x1F]')NON_ASCII = re.compile('[\x80-\xff]')class RobotRemoteServer(SimpleXMLRPCServer):allow_reuse_address = True_generic_exceptions = (AssertionError, RuntimeError, Exception)_fatal_exceptions = (SystemExit, KeyboardInterrupt)def __init__(self, library, host='127.0.0.1', port=8270, port_file=None, allow_stop=True):"""Configure and start-up remote server.:param library: Test library instance or module to host.:param host:Address to listen. Use ``'0.0.0.0'`` to listento all available interfaces.:param port:Port to listen. Use ``0`` to select a free portautomatically. Can be given as an integer or asa string.:param port_file:   File to write port that is used. ``None`` meansno such file is written.:param allow_stop:  Allow/disallow stopping the server using``Stop Remote Server`` keyword."""SimpleXMLRPCServer.__init__(self, (host, int(port)), logRequests=False)self._library = libraryself._allow_stop = allow_stopself._shutdown = Falseself._register_functions()self._register_signal_handlers()self._announce_start(port_file)self.serve_forever()def _register_functions(self):self.register_function(self.get_keyword_names)self.register_function(self.run_keyword)self.register_function(self.get_keyword_arguments)self.register_function(self.get_keyword_documentation)self.register_function(self.stop_remote_server)def _register_signal_handlers(self):def stop_with_signal(signum, frame):self._allow_stop = Trueself.stop_remote_server()for name in 'SIGINT', 'SIGTERM', 'SIGHUP':if hasattr(signal, name):signal.signal(getattr(signal, name), stop_with_signal)def _announce_start(self, port_file=None):host, port = self.server_addressself._log('Robot Framework remote server at %s:%s starting.'  % (host, port))if port_file:pf = open(port_file, 'w')try:pf.write(str(port))finally:pf.close()def serve_forever(self):if hasattr(self, 'timeout'):self.timeout = 0.5elif sys.platform.startswith('java'):self.socket.settimeout(0.5)while not self._shutdown:try:self.handle_request()except (OSError, select.error), err:if err.args[0] != errno.EINTR:raisedef stop_remote_server(self):prefix = 'Robot Framework remote server at %s:%s ' % self.server_addressif self._allow_stop:self._log(prefix + 'stopping.')self._shutdown = Trueelse:self._log(prefix + 'does not allow stopping.', 'WARN')return self._shutdowndef get_keyword_names(self):get_kw_names = getattr(self._library, 'get_keyword_names', None) or \   getattr(self._library, 'getKeywordNames', None)if self._is_function_or_method(get_kw_names):names = get_kw_names()else:names = [attr for attr in dir(self._library) if attr[0] != '_' and self._is_function_or_method(getattr(self._library, attr))]return names + ['stop_remote_server']def _is_function_or_method(self, item):# Cannot use inspect.isroutine because it returns True for# object().__init__ with Jython and IronPythonreturn inspect.isfunction(item) or inspect.ismethod(item)def run_keyword(self, name, args, kwargs=None):args, kwargs = self._handle_binary_args(args, kwargs or {})result = {'status': 'FAIL'}self._intercept_std_streams()try:return_value = self._get_keyword(name)(*args, **kwargs)except:exc_type, exc_value, exc_tb = sys.exc_info()self._add_to_result(result, 'error',self._get_error_message(exc_type, exc_value))self._add_to_result(result, 'traceback',self._get_error_traceback(exc_tb))self._add_to_result(result, 'continuable',self._get_error_attribute(exc_value, 'CONTINUE'),default=False)self._add_to_result(result, 'fatal',self._get_error_attribute(exc_value, 'EXIT'),default=False)else:try:self._add_to_result(result, 'return',self._handle_return_value(return_value))except:exc_type, exc_value, _ = sys.exc_info()self._add_to_result(result, 'error',self._get_error_message(exc_type, exc_value))else:result['status'] = 'PASS'self._add_to_result(result, 'output', self._restore_std_streams())return resultdef _handle_binary_args(self, args, kwargs):args = [self._handle_binary_arg(a) for a in args]kwargs = dict([(k, self._handle_binary_arg(v)) for k, v in kwargs.items()])return args, kwargsdef _handle_binary_arg(self, arg):if isinstance(arg, Binary):return arg.datareturn argdef _add_to_result(self, result, key, value, default=''):if value != default:result[key] = valuedef get_keyword_arguments(self, name):kw = self._get_keyword(name)if not kw:return []return self._arguments_from_kw(kw)def _arguments_from_kw(self, kw):args, varargs, kwargs, defaults = inspect.getargspec(kw)if inspect.ismethod(kw):args = args[1:]  # drop 'self'if defaults:args, names = args[:-len(defaults)], args[-len(defaults):]args += ['%s=%s' % (n, d) for n, d in zip(names, defaults)]if varargs:args.append('*%s' % varargs)if kwargs:args.append('**%s' % kwargs)return argsdef get_keyword_documentation(self, name):if name == '__intro__':return inspect.getdoc(self._library) or ''if name == '__init__' and inspect.ismodule(self._library):return ''return inspect.getdoc(self._get_keyword(name)) or ''def _get_keyword(self, name):if name == 'stop_remote_server':return self.stop_remote_serverkw = getattr(self._library, name, None)if not self._is_function_or_method(kw):return Nonereturn kwdef _get_error_message(self, exc_type, exc_value):if exc_type in self._fatal_exceptions:self._restore_std_streams()raisename = exc_type.__name__message = self._get_message_from_exception(exc_value)if not message:return nameif exc_type in self._generic_exceptions \or getattr(exc_value, 'ROBOT_SUPPRESS_NAME', False):return messagereturn '%s: %s' % (name, message)def _get_message_from_exception(self, value):# UnicodeError occurs below 2.6 and if message contains non-ASCII bytestry:msg = unicode(value)except UnicodeError:msg = ' '.join([self._str(a, handle_binary=False) for a in value.args])return self._handle_binary_result(msg)def _get_error_traceback(self, exc_tb):# Latest entry originates from this class so it can be removedentries = traceback.extract_tb(exc_tb)[1:]trace = ''.join(traceback.format_list(entries))return 'Traceback (most recent call last):\n' + tracedef _get_error_attribute(self, exc_value, name):return bool(getattr(exc_value, 'ROBOT_%s_ON_FAILURE' % name, False))def _handle_return_value(self, ret):if isinstance(ret, basestring):return self._handle_binary_result(ret)if isinstance(ret, (int, long, float)):return retif isinstance(ret, Mapping):return dict([(self._str(key), self._handle_return_value(value)) for key, value in ret.items()])try:return [self._handle_return_value(item) for item in ret]except TypeError:return self._str(ret)def _handle_binary_result(self, result):if not self._contains_binary(result):return resulttry:result = str(result)except UnicodeError:raise ValueError("Cannot represent %r as binary." % result)return Binary(result)def _contains_binary(self, result):return (BINARY.search(result) or isinstance(result, str) andsys.platform != 'cli' and NON_ASCII.search(result))def _str(self, item, handle_binary=True):if item is None:return ''if not isinstance(item, basestring):item = unicode(item)if handle_binary:return self._handle_binary_result(item)return itemdef _intercept_std_streams(self):sys.stdout = StringIO()sys.stderr = StringIO()def _restore_std_streams(self):stdout = sys.stdout.getvalue()stderr = sys.stderr.getvalue()close = [sys.stdout, sys.stderr]sys.stdout = sys.__stdout__sys.stderr = sys.__stderr__for stream in close:stream.close()if stdout and stderr:if not stderr.startswith(('*TRACE*', '*DEBUG*', '*INFO*', '*HTML*',  '*WARN*')):stderr = '*INFO* %s' % stderrif not stdout.endswith('\n'):stdout += '\n'return self._handle_binary_result(stdout + stderr)def _log(self, msg, level=None):if level:msg = '*%s* %s' % (level.upper(), msg)self._write_to_stream(msg, sys.stdout)if sys.__stdout__ is not sys.stdout:self._write_to_stream(msg, sys.__stdout__)def _write_to_stream(self, msg, stream):stream.write(msg + '\n')stream.flush()if __name__ == '__main__':import xmlrpclibdef stop(uri):server = test(uri, log_success=False)if server is not None:print 'Stopping remote server at %s.' % uriserver.stop_remote_server()def test(uri, log_success=True):server = xmlrpclib.ServerProxy(uri)try:server.get_keyword_names()except:print 'No remote server running at %s.' % urireturn Noneif log_success:print 'Remote server running at %s.' % urireturn serverdef parse_args(args):actions = {'stop': stop, 'test': test}if not args or len(args) > 2 or args[0] not in actions:sys.exit('Usage:  python -m robotremoteserver test|stop [uri]')uri = len(args) == 2 and args[1] or 'http://127.0.0.1:8270'if '://' not in uri:uri = 'http://' + urireturn actions[args[0]], uriaction, uri = parse_args(sys.argv[1:])action(uri)
  3. 下载SikuliRemoteLibrary.py放到[C:\robot\libs]里面 无语了sikuli好像也上去了,代码如下自行保存成SikuliRemoteLibrary

    import sys, osfrom robotremoteserver import RobotRemoteServer# from org.sikuli.script import *class SikuliRemoteLibrary:def __init__(self):self.log = ''# self.SS = Screen()  self.PT = Pattern()def count_items_in_directory(self, path):"""Returns the number of items in the directory specified by `path`."""return len([i for i in os.listdir(path) if not i.startswith('.')])def strings_should_be_equal(self, str1, str2):print "Comparing '%s' to '%s'" % (str1, str2)if str1 != str2:raise AssertionError("Given strings are not equal")#   def _wait(self, imgFile, timeOut, similarity):# try:#   self.PT = Pattern(imgFile)#   self.PT = self.PT.similar(float(similarity))#   self.SS.wait(self.PT, float(timeOut))# except FindFailed, err:#   print "ERR: _wait"#   raise AssertionError(err)#   def click_object(self, imgFile, timeOut, similarity):# try:#   self._wait(imgFile, timeOut, similarity)#   self.SS.click(imgFile)# except FindFailed, err:#   raise AssertionError("Cannot click [" + imgFile + "]")#   def object_exists(self, imgFile, similarity, timeOut):# try:#   self._wait(imgFile, timeOut, similarity)# except FindFailed, err:#   raise AssertionError("Could not find [" + imgFile + "]")#   def type_at_object(self, imgFile, txt, timeOut, similarity):# try:#   self._wait(imgFile, timeOut, similarity)#   self.SS.type(imgFile, txt)# except FindFailed, err:#   raise AssertionError("Cannot type at [" + imgFile + "]")#   def paste_at_object(self, imgFile, txt, timeOut, similarity):# try:#   self._wait(imgFile, timeOut, similarity)#   self.SS.paste(imgFile, txt)# except FindFailed, err:#   raise AssertionError("Cannot paste at [" + imgFile + "]")if __name__ == '__main__':SRL = SikuliRemoteLibrary()RobotRemoteServer(SRL, *sys.argv[1:])
  4. 复制 C:\Program Files\Sikuli X\sikuli-script.jar 到 C:\robot\libs
  5. C:\robot\libs\sikuli-script.jar加入JAVA_PATH
  6. 运行远端服务 cmd进入c:\robot\libs 然后 Jython.bat SikuliRemoteLibrary.py
  7. 进入RIDE
  8. create 项目
  9. create testsuit
  10. 脚本如下:

    *** Settings ***  Documentation Integrating Selenium, Sikuli into Robot Framework  Test SetupLogin To Yahoo Mail${user_name}${password}  Test Teardown Tear Test Down  Library   Selenium2Library15# Selenium library  Library   Remotehttp://localhost:${port}# Sikuli  Library   Screenshot# Taking screenshots when a test fails  *** Variables ***  ${url}http://mail.yahoo.com# Yahoo mail URL  ${browser}ff# Browser  ${user_name}  user_name# User name  ${password}   password# Password  ${port}   8270# Default port number for the remote server  ${data_path}  c:\robot\data# Sikuli images  ${similarity} 0.90# Used in Sikuli image comparison  ${timeout}10# Time to wait for objects  *** Testcases ***  login To Yahoo Mail Test Case  Wait Until Page Contains Elementyuhead-sform-searchfield${timeout}  Input Textyuhead-sform-searchfieldENGLISH  Object Exists${data_path}\search_box_left.png${similarity}  *** Keywords ***  Login To Yahoo Mail  [Arguments]${user}${pass}  [Documentation]This keyword logs user into Yahoo mail  Open Browser${url}${browser}  Wait Until Page Contains Elementusername  Input Textusername${user}  Input Passwordpasswd${pass}  Click Button.save  Wait Until Page Contains Elementtoolbar  Click Object${data_path}\maximize.png  Sleep1  Tear Test Down  Run Keyword If Test FailedTake Screenshot  Close All Browsers  

应用sikuli remote library的python脚本如下

    import sys    from robotremoteserver import RobotRemoteServer    from org.sikuli.script import *    class SikuliRemoteLibrary:        def __init__(self):            self.SS = Screen()            self.PT = Pattern()        def _wait(self, imgFile, timeOut, similarity):        try:            self.PT = Pattern(imgFile)            self.PT = self.PT.similar(float(similarity))            self.SS.wait(self.PT, float(timeOut))        except FindFailed, err:            print "ERR: _wait"            raise AssertionError(err)        def click_object(self, imgFile, timeOut, similarity):        try:            self._wait(imgFile, timeOut, similarity)            self.SS.click(imgFile)        except FindFailed, err:            raise AssertionError("Cannot click [" + imgFile + "]")        def object_exists(self, imgFile, similarity, timeOut):        try:            self._wait(imgFile, timeOut, similarity)        except FindFailed, err:            raise AssertionError("Could not find [" + imgFile + "]")        def type_at_object(self, imgFile, txt, timeOut, similarity):        try:            self._wait(imgFile, timeOut, similarity)            self.SS.type(imgFile, txt)        except FindFailed, err:            raise AssertionError("Cannot type at [" + imgFile + "]")        def paste_at_object(self, imgFile, txt, timeOut, similarity):        try:            self._wait(imgFile, timeOut, similarity)            self.SS.paste(imgFile, txt)        except FindFailed, err:            raise AssertionError("Cannot paste at [" + imgFile + "]")    if __name__ == '__main__':        SRL = SikuliRemoteLibrary()        RobotRemoteServer(SRL, *sys.argv[1:])

3、搭建持续集成环境CI(Continuous Intergration)

  1. 新建 [C:\robot\arg] 存放要传入的变量

  2. 新建C:\robot\argarg.txt 内容如下:

    –variable user_name:user_name
    –variable password:pass_word
    –outputdir ..\out

  3. 新建 C:\robot\run

  4. 创建 run.bat内容如下:

    call pybot.bat –argumentfile C:\robotarg\arg.txt C:\robot\suites\test.txt

  5. 安装Jenkins

    • 下载地址:jenkins.war
    • 运行jenkins java -jar jenkins.war --httpPort=80
  6. Robotframwork集成Jenkins Plugin

    • 下载https://code.google.com/p/robotframework-javatools/downloads/detail?name=robotframework.hpi
    • 运行java -jar jenkins.war -httpport=80
    • 浏览器访问http://localhost:8080
    • 进入manage Jenkins
    • 进入Mange Plugins
    • 点击 Advanced
    • 点击Upload Plugins选择robotframework.hpi后点击upload
    • 重启jenkins
  7. 创建Jenkins 任务

    • 进入http://localhost:8080
    • 点击NewJob
    • 输入 任务名称,选择”Build a free-style software project”
    • 选择 Add build step
    • 点击 Execute windows batch command
    • 输入 :

      cd C:\robot\run
      call run.bat

    • 选择Add post-build action

    • 点击Publish Robot Framework test results
    • 设置”Directory of Robot output” as “..\out”
    • 设置 “Log/Report link” as “log.html”
    • 设置Output xml name” as “output.xml”
    • 设置 “Report html name” as “report.html”
    • 设置 “Log html name” as “log.html”

到现在,我们已经jenkins已经可以开始工作了。确保Sikuliremotelibrary已经运行,现在可以开始build测试任务了。

0 0
原创粉丝点击