RobotFramework中创建自定义Library的方法 (二)
介绍另一种方式在RF中创建可被识别和调用的关键字方法。
借鉴AppiumLibrary和RF内置关键字的编写方法:
使用这种方式创建自定义库需要注意以下几点:
1. 库的名称与初始化类的名称相同
2. 初始化类在多重继承时选择需要的功能类
3. 关键方法的构造类可继承KeywordGroup类,该类的方法参见AppiumLibrary,文中我会给出具体的代码实现,可以自建一个py文件代替。
详细内容如下:
主程序代码:
from Connect import *
from Start import *
class TestLibrary(Connect,
Start):
"""
#注释1.
使用多重继承的方式,在此处加载所有自建类的方法
这里举例只加了Connect和Start,根据自己需要增加
此处的TestLibrary也可以不写,写成__init__
关键是整个文件夹的名称要和你定义的库名称保持一致,才可以被RF识别调用
"""
ROBOT_LIBRARY_SCOPE = "GLOBAL"
ROBOT_LIBRARY_VERSION = VERSION
def __init__(self):
for base in TestLibrary.__bases__:
base.__init__(self)
#注释2. 此处的初始化让继承所有父类都执行相应的初始化
功能类代码:
创建的Connect.py文件:
from keywordgroup import KeywordGroup
class TestConnect(KeywordGroup):
def __init__(self):
pass
#根据需要可自行进行增加
def connect(self, connect_way):
self.serialobject.Open()
创建的Start.py文件:
class TestStart(KeywordGroup):
def __init__(self):
pass
#根据需要可自行进行增加
def start(self, connect_way):
self.serialobject.Start()
对于注释1,这种构造关键字的方式其实就是继承所有父类的对象和方法,需要确保父类的方法不重名,否则Python中的多重继承是按照从左往右依次继承,方法重名则被覆盖调用,到时候你都不知道调用的是哪一个。
有关多重继承的坑详见:对于注释2,该步骤的目的是将所有的继承类进行初始化操作,可以在这一步实例化所有对象。
文中的base打印出来其实就是Connect和Start创建的类:TestConnect和TestStart:
<class 'TestLibrary.Connect.TestConnect'>
<class 'TestLibrary.Start.TestStart'>
大家可以看到,在创建功能类的时候,每个类都继承了KeywordGroup类,该方法是借鉴AppiumLibrary的实现行为,当然我在查看了RF的BuildIn功能后,发现不用该方法也可以,在BuiltIn.py文件中是这么构造内置类的:
class BuiltIn(_Verify, _Converter, _Variables, _RunKeyword, _Control, _Misc):
ROBOT_LIBRARY_SCOPE = 'GLOBAL'
ROBOT_LIBRARY_VERSION = get_version()
RF内置的方法也是通过直接继承各个方法类来调用,因此仅靠继承的方式,在RF中也已经可以调用所有方法。之所以让大家在方法类中继承KeywordGroup是为了在出错时可以更好的查找原因。对应的也就是BuiltIn.py文件中RobotNotRunningError类的实现,具体实现详见下方:
关键字基类:KeywordGroup的代码实现:
# -*- coding: utf-8 -*-
import sys
import inspect
try:
from decorator import decorator
except SyntaxError: # decorator module requires Python/Jython 2.4+
decorator = None
if sys.platform == 'cli':
decorator = None # decorator module doesn't work with IronPython 2.6
def _run_on_failure_decorator(method, *args, **kwargs):
try:
return method(*args, **kwargs)
except Exception as err:
self = args[0]
if hasattr(self, '_run_on_failure'):
self._run_on_failure()
raise
class KeywordGroupMetaClass(type):
def __new__(cls, clsname, bases, dict):
if decorator:
for name, method in dict.items():
if not name.startswith('_') and inspect.isroutine(method):
dict[name] = decorator(_run_on_failure_decorator, method)
return type.__new__(cls, clsname, bases, dict)
class KeywordGroup(object):
__metaclass__ = KeywordGroupMetaClass
可以将该代码复制后丢到一个文件中,命名为keywordgroup,在方法类中导入并继承即可。
如果不按照这种方式实现,大家也可以再去看一下RF中的BuildIn.py文件,其实也有一个基类:_BuiltInBase,在其中有这样一个方法:
def _get_context(self, top=False):
ctx = EXECUTION_CONTEXTS.current if not top else EXECUTION_CONTEXTS.top
if ctx is None:
raise RobotNotRunningError('Cannot access execution context')
return ctx
其中RobotNotRunningError的具体方法实现和KeywordGroup的方法类似。
按照上述方法创建主程序和功能类,采用继承的方式,将整个文件夹放在D:\Python\Lib\site-packages路径下(即你安装的Python路径),即可在RF中导入库进行使用了。