1. 程式人生 > >RobotFramework之Python呼叫RF關鍵字

RobotFramework之Python呼叫RF關鍵字

背景

這個需求說實話是有那麼些奇葩,因為正常的框架不會用到這個需求,要麼就純Python來實現,要麼就純RobotFramework來實現,用RobotFramework的時候是可以正常呼叫Python的,但是反過來就有點蛋疼了。

我們現在的框架就是基於RobotFramework實現的,但是由於RobotFramework在某些地方的擴充套件性太低,某些時候用Python來實現更為高效,不過現有的RobotFramework工程已經有非常多的沉澱了,要是把這部分全部重寫,工作量太大了,因此就有了這麼個奇葩的需求。在網上搜索了大半天后,終於還是放棄了,只能自己去看原始碼來實現了。

簡單粗暴的實現

有一種非常簡單粗暴的實現方式,用RobotFramework寫一個測試用例,然後這個用例呼叫對應的關鍵字,再用Python來執行這條用例,就實現了呼叫關鍵字的功能,但是這樣有兩個弊端。

  1. 每次呼叫關鍵字都要寫測試用例,非常麻煩
  2. 如果要獲取返回值,就很蛋疼了

更為優雅的實現

整個部分實現起來其實不難,只不過RobotFramework的原始碼沒有什麼人去解讀,也沒有很好的翻譯文件,其實在之前的解析文章中用到的robot.api中就已經涉及到這個點了,實現程式碼如下:

class RobotAbout(object):
    """
    呼叫RobotFramework的方法
    eg:
    ra = RobotAbout.RobotAbout()
    ra.exec_keywords('xxx.robot', ['獲取隨機數', '獲取計數'])
    """
def exec_keyword(self, path_to_file, keyword, arg=None): """ 執行RobotFramework的關鍵字 :param path_to_file: String,RobotFramework檔案的路徑,一般是執行檔案的相對路徑,絕對路徑也可以 :param keyword: String,執行的關鍵字 :param arg: List[String], 執行關鍵字的引數,如果沒有則不傳 :return: None, 沒有返回則表示執行通過,可以檢視執行檔案目錄下的log.html來定位問題 """
suite = TestSuite('Test') suite.resource.imports.resource(path_to_file) test = suite.tests.create('TEST', tags=['smoke']) if arg: if isinstance(arg, list): test.keywords.create(keyword.decode('utf-8'), args=arg) else: raise TypeError('args must be list') else: test.keywords.create(keyword.decode('utf-8')) result = suite.run(critical='smoke') if result.suite.status == 'PASS': pass else: ResultWriter('test.xml').write_results()

給我靈感的頁面就在官方的說明文件上,這裡有一段非常有意思的說明:

這裡提供了兩種方式執行RobotFramework,一種是用TestSuiteBuilder,這種其實跟我們之前的方法沒啥區別,都是執行一個測試用例,第二種方法則是用Python來寫一個RobotFramework的測試用例,這種思路可以通過抽象成一個類,就可以達到優雅的執行RobotFramework的關鍵字了。

需要注意,官方文件寫的是suite.resource.imports.library,而RobotFramework的檔案引用都是要用Resource來引用的,不能原樣照搬。所以這裡我們要去看它的原始碼來實現:

robot.running.model.py

class ResourceFile(object):

    def __init__(self, doc='', source=None):
        self.doc = doc
        self.source = source
        self.imports = []
        self.keywords = []
        self.variables = []

    @setter
    def imports(self, imports):
        return model.Imports(self.source, imports)

    @setter
    def keywords(self, keywords):
        return model.ItemList(UserKeyword, items=keywords)

    @setter
    def variables(self, variables):
        return model.ItemList(Variable, {'source': self.source}, items=variables)

從這裡我們能看到,imports是由一個裝飾器@setter來處理的,那麼只要跟進它的方法就能看到:

robot.model.imports.py

class Imports(ItemList):

    def __init__(self, source, imports=None):
        ItemList.__init__(self, Import, {'source': source}, items=imports)

    def library(self, name, args=(), alias=None):
        self.create('Library', name, args, alias)

    def resource(self, path):
        self.create('Resource', path)

    def variables(self, path, args=()):
        self.create('Variables', path, args)

這裡就告訴了我們,import這個列表中可以放libraryresourcevariables

因此在這裡我們只要把原始碼改成suite.resource.imports.resource(path_to_file)就可以正常的引用RobotFramework的關鍵字了。

其他注意點

在除錯的過程中我發現一個問題,如果關鍵字用中文編寫,那麼必須要把呼叫的關鍵字編碼成utf-8,否則會報錯找不到關鍵字。就像上面的程式碼這樣處理:

test.keywords.create(keyword.decode('utf-8'), args=arg)

或者如果你不在方法中處理,也可以這樣傳入引數:

ra.exec_keyword('../xxx/xxx.robot', u'獲取隨機數')