解决Robot Framework包自定义关键字的初始化和可访问性问题

我正在开发一个名为 ApxxRobotFrameworkApiPackage 的 Robot Framework 包,用于进行 API 测试。该包包含自定义关键字,其中之一名为 SendGETRequest,用于发送 GET 请求。

项目结构如下:

ApppRobotFrameworkApiPackage/
├── __init__.py
└── Resources/
     └── robot_resources/
          └── custom_keywords.robot

这些关键字应该从 init.py 文件中暴露出来。最终,该包将被上传到 Azure DevOps Artifact,并通过 pip install 安装到不同的测试项目中。但是目前关键字 "SendGETRequest" 在 init.py 文件中无法访问。

以下是 init.py 文件中代码的概要版本:

import sys
from robot.api import TestSuite
from robot.libraries.BuiltIn import BuiltIn
sys.path.append('/Users/samuelcheng/Documents/Atlantis-Robotframework-Package/ApppRobotFrameworkApiPackage/')

class ApppRobotFrameworkApiPackage:
    def __init__(self, portal=None, useFiddlerProxies=False, *otherSettings):
        """
        这是该包的初始化。
        在导入包的瞬间,此部分代码将被执行。
        其目的是基于使用的门户配置一些设置。

        输入:
        - Portal:这是应用程序运行的门户名称。
                   当前选项在变量 portalOptions 下。
                   如果测试人员希望在其他门户中使用此包,应将设置添加到此函数。
                   默认值为 None。
        - useFiddlerProxies:这决定是否使用 Fiddler 代理。
                            在设置 API 测试时,Fiddler 非常有用,但由于目前(当前)在 Azure 中不可用,
                            在流水线运行时不应使用代理。
        - otherSettings:这是可以提供其他配置设置的地方。
                         例如,用于测试的 __FiscaalNummer 和 __SelectedWerkgeverNaam。
        """
        global proxies
        global url
        global cookiesTemplate
        global headersTemplate
        global endpointPreflight

        portalOptions = ["test", "test", "KCC Inkijk"]
        if useFiddlerProxies:
            proxies = {'http': "127.0.0.1:8888", 'https': "127.0.0.1:8888"}
        else:
            proxies = None
        if portal in portalOptions:
            if portal == 'Werknemersportaal':
                url = "https://test-netcore.otod.t-dc.ba.test.nl"
                cookiesTemplate = {'(.AspNetCore.Antiforgery.[a-zA-Z0-9=_-]*)': None, 'EWSESSION-T': None,
                                   'EWSESSION-T_S': None, 'XSRF-TOKEN': None}
                headersTemplate = {'XSRF-TOKEN': None, 'X-XSRF-TOKEN': None,
                                   'Content-Type': 'application/json;charset=UTF-8'}
                endpointPreflight = "/kias/mijnbezwaar/api/bezwaarschriften/getcurrentbezwaarschrift"
                # TODO: test url
                # TODO: logout
            elif portal == 'test':
                url = "https://test.otod.t-dc.ba.test.nl"
                cookiesTemplate = {'ASP.NET_SessionId': None, 'WerkgeverSamlAuthT': None, 'WerkgeverSamlAuthT1': None,
                                   '__FiscaalNummer': otherSettings[0], '__SelectedWerkgeverNaam': otherSettings[1]}
                endpointPreflight = "/bezwaarenberoep/api/bezwaar/getbezwaarschriften"
            elif portal == "KCC Inkijk":
                url = "https://test-netcore.otod.t-dc.ba.test.nl"
                cookiesTemplate = {'(.AspNetCore.Antiforgery.[a-zA-Z0-9=_-]*)': None, 'KCCINKIJK': None,
                                   'XSRF-TOKEN': None}
                headersTemplate = {'X-XSRF-TOKEN': None, 'Content-Type': 'application/json;charset=UTF-8'}
            else:
                BuiltIn().log_to_console(
                    str(portal) + " 不是此包的有效门户。当前可用的门户为:" + str(portalOptions))

            self._requests_library = None
            #   ---------------------------------------------------------------------------
            # # 将 custom_keywords.robot 文件加载为测试套件
            # self.suite = TestSuite()
            # self.suite.resource.imports.resource = 'custom_keywords.robot'

            # # 在包中暴露自定义关键字
            # self.SendGETRequest = self.suite.resource.keywords["SendGETRequest"]

            # # 这允许用户直接从包名导入并使用自定义关键字
            # __all__ = [
            #     "ApppRobotFrameworkApiPackage",  # 类名
            #     "SendGETRequest"
            # ]
            #   ----------------------------------------------------------------------------

            # # 使用库语法从 custom_keywords.robot 导入自定义关键字
            # resource_path = "ApppRobotFrameworkApiPackage/custom_keywords.robot"
            # TestSuite().resource.imports.library(resource_path)

            # 将 custom_keywords.robot 文件加载为测试套件
            self.suite = TestSuite()

            # 使用库语法导入自定义关键字
            resource_path = "ApppRobotFrameworkApiPackage/Resources/robot_resources/custom_keywords.robot"
            self.suite.resource.imports.library(resource_path)

            # 在包中暴露自定义关键字
            self.SendGETRequest = self.suite.resource.keywords["SendGETRequest"]
            BuiltIn().log_to_console("SendGETRequest 关键字:", self.SendGETRequest)
            sys.stdout.flush()

            # 这允许用户直接从包名导入并使用自定义关键字
            __all__ = [
                "ApppRobotFrameworkApiPackage",  # 类名
                "SendGETRequest"
            ]

    def get_requests_library(self):
        """
        由于 Requests Library 是一个具有状态的库,为确保在整个代码中继续使用相同的会话,
        我们必须使用一个库实例。
        首先检查是否已经有一个库实例(最初设置为 None)。
        如果尚未创建实例,将创建并返回一个新实例。
        否则,将返回已创建的库实例。
        """
        if self._requests_library is None:
            self._requests_library = BuiltIn().get_library_instance('RequestsLibrary')
        return self._requests_library
   

custom_keywords.robot

*** Settings ***
Library    BuiltIn
Library    RequestsLibrary

*** Keywords ***
SendGETRequest
    [Arguments]    ${endpoint}    ${headers}
    ${session}    Create Session    mysession   endpoint=${endpoint}   headers=${headers}
    ${response}=    GET On Session    mysession    url=${endpoint}    headers=${headers}    expected_status=anything
    Set Suite Variable    ${response}
    ${status}    ${response_body}=    Run Keyword And Ignore Error    Evaluate    json.dumps(${response.json()})
    Run Keyword If    '${status}' == 'FAIL'    Set Variable    ${response_body}    '{}'
    Set Suite Variable    ${response_body}
    [Return]    ${response}
 

自定义关键字 SendGETRequest 如何可以被访问?

从你提供的代码和描述中,你正在开发一个名为 ApxxRobotFrameworkApiPackage 的 Robot Framework 包,并尝试从该包中的 init.py 文件中导出自定义关键字 SendGETRequest。在你的代码中,你已经尝试了几种方式来暴露这个关键字,但似乎还没有达到预期的结果。

根据你的代码,你可以尝试以下方法来确保你的自定义关键字 SendGETRequest 可以被访问:

  1. 更新 __all__ 列表:
    请确保在 __init__.py 文件中更新 __all__ 列表,以包含你希望导出的所有类、函数和变量。在你的代码中,将以下代码添加到 __init__.py 文件中,以确保 SendGETRequest 被正确导出:

    __all__ = [
        "ApppRobotFrameworkApiPackage",  # 类名
        "SendGETRequest"
    ]
    
  2. 检查导入路径:
    确保 custom_keywords.robot 文件的路径是正确的。在你的 init.py 文件中,你使用了以下代码来导入自定义关键字:

    resource_path = "ApppRobotFrameworkApiPackage/Resources/robot_resources/custom_keywords.robot"
    self.suite.resource.imports.library(resource_path)
    

    确保路径是正确的,并且能够正确地找到 custom_keywords.robot 文件。

  3. 确认包名和导入路径:
    确保你的包名和导入路径都是正确的。在你的 __init__.py 文件中,确保你正确地导入了你的自定义关键字类和函数,如下所示:

    from .robot_resources import custom_keywords
    
  4. 检查包路径:
    在你的 init.py 文件中,你使用了以下代码将包的路径添加到 sys.path

    sys.path.append('/Users/samuelcheng/Documents/Atlantis-Robotframework-Package/ApppRobotFrameworkApiPackage/')
    

    确保路径是正确的,并且能够正确地找到你的包。

  5. 检查 __init__.py 是否被正确调用:
    确保 __init__.py 文件被正确调用。这可以通过在 __init__.py 文件中添加一些输出或打印语句来验证。确保你的自定义关键字类和函数被正确地初始化和导出。

引用chatgpt内容作答:
看起来你的代码中存在一些问题,导致自定义关键字 "SendGETRequest" 在 init.py 文件中无法访问。以下是你可以尝试的一些修复步骤:

1、修正包的初始化代码:

首先,你需要确保在初始化 ApppRobotFrameworkApiPackage 类时正确加载和暴露自定义关键字。你可以按照你注释中的第一种尝试,将以下代码添加到 init.py 文件中:

from robot.api import TestSuite

class ApppRobotFrameworkApiPackage:
    def __init__(self, portal=None, useFiddlerProxies=False, *otherSettings):
        # 初始化代码...

        # 将 custom_keywords.robot 文件加载为测试套件
        self.suite = TestSuite()
        resource_path = "ApppRobotFrameworkApiPackage/Resources/robot_resources/custom_keywords.robot"
        self.suite.resource.imports.library(resource_path)

        # 在包中暴露自定义关键字
        self.SendGETRequest = self.suite.resource.keywords["SendGETRequest"]

        # 其他初始化代码...

然后,在类定义的末尾,添加以下代码以确保关键字可以直接从包中导入:

__all__ = [
    "ApppRobotFrameworkApiPackage",
    "SendGETRequest"
]

2、修正 custom_keywords.robot 文件:

确保 custom_keywords.robot 文件中的关键字定义是正确的。你的 SendGETRequest 关键字看起来是正确的。

3、在其他地方导入并使用关键字:

一旦你的包初始化和关键字暴露的问题解决了,你可以在其他测试项目中导入并使用这些关键字,就像使用任何其他库一样:

*** Settings ***
Library    ApppRobotFrameworkApiPackage

*** Test Cases ***
Example Test
    ${response}=    SendGETRequest    /api/endpoint    headers=${headers}
    Log    Response: ${response}

4、确认路径设置:

确保路径设置是正确的。在初始化函数中,你使用了硬编码的路径,这可能在不同环境中导致问题。最好使用相对路径,这样在不同的项目中也能正常工作。

通过按照这些步骤检查和修复你的代码,你应该能够正确暴露并访问自定义关键字 "SendGETRequest"。如果问题仍然存在,确保在初始化和导入的过程中没有发生其他错误。

【以下回答由 GPT 生成】

问题的关键在于如何正确地从 __init__.py 文件中导入和暴露自定义关键字。

以下是一种解决方案:

  1. 确保 custom_keywords.robot 文件位于正确的位置。根据目录结构,它应该位于 ApppRobotFrameworkApiPackage/Resources/robot_resources/
  2. __init__.py 文件顶部添加以下行,将资源文件夹添加到 sys.path 中:
import os
sys.path.append(os.path.join(os.path.dirname(__file__), "Resources/robot_resources"))
  1. __init__.py 文件中导入并初始化自定义关键字。以 "SendGETRequest" 关键字为例,在 __init__ 方法中添加以下代码:
import custom_keywords

class ApppRobotFrameworkApiPackage:
    def __init__(self, portal=None, useFiddlerProxies=False, *otherSettings):
        # 其他代码...

        custom_keywords.init_keywords()
  1. custom_keywords.robot 文件中定义 "SendGETRequest" 关键字。请确保关键字函数以 def 关键字开头,并使用 @keyword 装饰器进行修饰。以下是一个简单的示例:
from robot.api.deco import keyword
from robot.libraries.BuiltIn import BuiltIn

@keyword
def send_get_request(url):
    # 发送 GET 请求的代码...
    pass

def init_keywords():
    # 初始化自定义关键字
    BuiltIn().import_library(custom_keywords)
  1. 确保 custom_keywords.robot 文件名与 import_library 方法中的参数相匹配。

通过以上的解决方案,你应该能够从 __init__.py 文件中成功导入和初始化自定义关键字,并且关键字 "SendGETRequest" 应该可以在该文件中正常访问。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:为了使自定义关键字SendGETRequest可以在包的初始化中被访问,您可以采取以下步骤:
1、 在init.py文件中,确保正确加载和导入custom_keywords.robot文件。您可以使用以下代码替换您目前注释掉的部分,代码如下:

# 将 custom_keywords.robot 文件加载为测试套件
self.suite = TestSuite()
self.suite.resource.imports.library("ApppRobotFrameworkApiPackage.Resources.robot_resources.custom_keywords")

# 在包中暴露自定义关键字
self.SendGETRequest = self.suite.resource.keywords["SendGETRequest"]

# 这允许用户直接从包名导入并使用自定义关键字
__all__ = [
    "ApppRobotFrameworkApiPackage",  # 类名
    "SendGETRequest"
]

2、 确保custom_keywords.robot文件的路径正确。

根据您提供的项目结构,custom_keywords.robot 文件位于 Resources/robot_resources 文件夹下,因此在 __init__.py 文件中正确指定路径为 "ApppRobotFrameworkApiPackage.Resources.robot_resources.custom_keywords"
这样做将确保在初始化包时,关键字 "SendGETRequest" 可以被访问和使用。


另外,您还可以考虑以下改进:

  • sys.path.append() 的路径更改为相对路径,以避免依赖于绝对路径。
  • custom_keywords.robot 文件中的 *** Keywords *** 部分,使用 Library 语句导入 BuiltInRequestsLibrary 库不是必需的,因为它们已经在 __init__.py 文件中导入。您可以删除这些 Library 语句。

请注意,这里提供的解决方案是基于您提供的代码和项目结构。如果您的项目结构或其他配置有所不同,可能需要进行相应的调整。


如果以上回答对您有所帮助,点击一下采纳该答案~谢谢

援引讯飞星火:
问题出在 __init__.py 文件中,你需要将暴露自定义关键字的代码放在 __init__.py 文件的末尾,而不是在类定义的中间。以下是修改后的 __init__.py 文件:

import sys
from robot.api import TestSuite
from robot.libraries.BuiltIn import BuiltIn
sys.path.append('/Users/samuelcheng/Documents/Atlantis-Robotframework-Package/ApppRobotFrameworkApiPackage/')

class ApppRobotFrameworkApiPackage:
    # ... 省略其他代码 ...

    def get_requests_library(self):
        """
        由于 Requests Library 是一个具有状态的库,为确保在整个代码中继续使用相同的会话,
        我们必须使用一个库实例。
        首先检查是否已经有一个库实例(最初设置为 None)。
        如果尚未创建实例,将创建并返回一个新实例。
        否则,将返回已创建的库实例。
        """
        if self._requests_library is None:
            self._requests_library = BuiltIn().get_library_instance('RequestsLibrary')
        return self._requests_library

# 将 custom_keywords.robot 文件加载为测试套件
self.suite = TestSuite()

# 使用库语法导入自定义关键字
resource_path = "ApppRobotFrameworkApiPackage/Resources/robot_resources/custom_keywords.robot"
self.suite.resource.imports.library(resource_path)

# 在包中暴露自定义关键字
self.SendGETRequest = self.suite.resource.keywords["SendGETRequest"]
BuiltIn().log_to_console("SendGETRequest 关键字:", self.SendGETRequest)
sys.stdout.flush()

# 这允许用户直接从包名导入并使用自定义关键字
__all__ = [
    "ApppRobotFrameworkApiPackage",  # 类名
    "SendGETRequest"
]

这样,自定义关键字 SendGETRequest 应该可以被访问了。


from .Resources.robot_resources.custom_keywords import SendGETRequest
from robot.api import TestSuite
from robot.libraries.BuiltIn import BuiltIn

class ApppRobotFrameworkApiPackage:
    def __init__(self, portal=None, useFiddlerProxies=False, *otherSettings):
        # ... 你的初始化代码 ...

        # 将 custom_keywords.robot 文件加载为测试套件
        self.suite = TestSuite()

        # 使用库语法导入自定义关键字
        resource_path = "ApppRobotFrameworkApiPackage/Resources/robot_resources/custom_keywords.robot"
        self.suite.resource.imports.library(resource_path)

        # 在包中暴露自定义关键字
        self.SendGETRequest = self.suite.resource.keywords["SendGETRequest"]

robot framework自定义以及使用关键字
可以参考下


Robot Framework官方教程(二)自定义关键字_robotframework自定义关键字_肥叔菌的博客-CSDN博客 1.新建文件夹新建一个文件夹,我的MyLibrary,并且存放在site-packages下2.编写代码在python的编译器中把需要的代码编写完成,并且运行成功,以下代码就是获取页面的session,生成随机数,拿到session+key+随机数,生成MD5,在和请求一起get请求,返回验证码,代码在本地编译没有问题import randomimport hashlibimport typesimport requestskey="XXXXXXXXX"class verificatio_robotframework自定义关键字 https://blog.csdn.net/asmartkiller/article/details/118916621

使用 self.suite.resource.imports.resource(resource_path) 来导入资源文件
使用 self.suite.resource.keywords.create(“SendGETRequest”) 来创建一个关键字对象
试试呢

可以加入环境变量,引入这个资源。

参考结合GPT4.0、文心一言,如有帮助,恭请采纳。

需要确保你的Python环境可以找到requests库,并且你的测试环境可以找到test_library.py。

# test_cases.robot  
  
*** Settings ***  
Library    test_library.py  
  
*** Test Cases ***  
Test GET Request  
    SendGETRequest    https://example.com/api/endpoint    {'Accept': 'application/json'}

然后定义一个名为"SendGETRequest"的关键字:

# test_library.py  
  
from robot.libraries.BuiltIn import BuiltIn  
from requests import Session  
from requests.exceptions import ConnectionError  
import json  
  
class TestLibrary:  
    def __init__(self):  
        self._ BuiltIn = BuiltIn()  
        self.session = Session()  
  
    def SendGETRequest(self, endpoint, headers=None):  
        if headers is None:  
            headers = {}  
        try:  
            response = self.session.get(endpoint, headers=headers)  
            self._BuiltIn.set_suite_variable('response', response)  
            status = response.status_code  
            response_body = json.dumps(response.json()) if response.content else '{}'  
            self._BuiltIn.set_suite_variable('response_body', response_body)  
            return response  
        except ConnectionError:  
            self._BuiltIn.set_suite_variable('response', 'connection_error')  
            return 'connection_error'

用SendGETRequest关键字时,使用库的实例来访问它。在上述示例中,ApxxRobotFrameworkApiPackage是您的库,您将其实例化为${api},因此您可以通过${api.SendGETRequest}来调用关键字

结合GPT给出回答如下请题主参考
要解决自定义关键字初始化和访问性问题,你可以按照以下步骤进行:

  1. 创建一个名为 ApxxRobotFrameworkApiPackage 的文件夹,并在文件夹中创建一个名为 __init__.py 的文件,这将使该文件夹成为 Python 包。

  2. __init__.py 文件中,你可以定义一个方法,该方法将初始化你的自定义关键字,例如 init_keywords()

  3. 在自定义关键字中导入该方法,并在自定义关键字之前调用该方法。

  4. 为了提高可访问性,你可以将 ApxxRobotFrameworkApiPackage 添加到你的 PYTHONPATH 环境变量中,这将使 Robot Framework 在运行时能够找到该包。

以下是 __init__.py 文件的示例代码:

from .keywords import SendGETRequ  # 导入自定义关键字

def init_keywords():
    # 初始化关键字
    SendGETRequ()

以下是自定义关键字文件的示例代码:

from ApxxRobotFrameworkApiPackage import init_keywords

init_keywords()  # 在关键字之前调用初始化方法

def SendGETRequ():
    # 发送 GET 请求的代码

如果你已将 ApxxRobotFrameworkApiPackage 添加到 PYTHONPATH 中,那么在你的 Robot Framework 测试套件中,你只需要导入自定义关键字并使用它:

*** Settings ***
Library    ApxxRobotFrameworkApiPackage.keywords

*** Test Cases ***
Example Test
    Send GET Requ

在 Robot Framework 中,自定义关键字需要被定义在一个 .py 文件中,并且在该文件中使用 def 语句定义函数。然后,该 .py 文件需要在你的包目录下,并在 init.py 文件中导入并暴露出去。

参考结合AI智能、文心一言,如对您有帮助,恭请采纳。

在Robot Framework中,包可以用来组织和管理关键字。包中的关键字可以是Python类或函数。

在包中定义自定义关键字时,有两个主要问题需要解决:初始化问题和可访问性问题。

  1. 初始化问题

当我们定义自定义关键字时,有时需要在关键字的执行前完成一些初始化工作,例如连接数据库或打开文件等。我们可以使用类的__init__方法或者Python中的模块级别函数来完成这些初始化工作。

示例:

# MyLibrary.py

class MyLibrary:
    def __init__(self):
        self.db = Database()
        self.file = open('myfile.txt', 'r')
    
    def connect_to_database(self):
        # Connect to database
        pass

    def read_file(self):
        # Read file
        pass

在上述示例中,我们在类的__init__方法中初始化了数据库连接和文件对象。这样,在我们调用MyLibrary中的其他关键字时,这些初始化工作已经完成了。

  1. 可访问性问题

默认情况下,Robot Framework将自定义关键字路径添加到Python的sys.path中。这意味着我们可以在测试套件中使用自定义关键字。但是,我们不能在其他Python脚本中使用这些自定义关键字,因为它们不在Python的sys.path中。

解决这个问题的一种方法是将自定义关键字路径添加到Python的sys.path中。我们可以在测试套件的引入部分中使用类似于以下的代码:

*** Settings ***
Library    path/to/MyLibrary.py

*** Variables ***
${DB_NAME}    my_db

但是,这种方法有一个问题,那就是在测试套件中的所有测试用例中都需要将关键字路径添加到sys.path中。这很麻烦,并且可能会导致代码重复和维护问题。

另一种解决方法是使用Robot Framework的扩展API来动态添加关键字路径。我们可以在MyLibrary.py中添加以下代码:

# MyLibrary.py

import sys
import os

path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
if path not in sys.path:
    sys.path.insert(0, path)

class MyLibrary:
    def __init__(self):
        self.db = Database()
        self.file = open('myfile.txt', 'r')
    
    def connect_to_database(self):
        # Connect to database
        pass

    def read_file(self):
        # Read file
        pass

在上述示例中,我们将自定义关键字路径添加到sys.path中,并确保它只添加一次。

这样,我们就可以在其他Python脚本中引入MyLibrary.py,并使用其中的自定义关键字。

通过解决初始化问题和可访问性问题,我们可以更好地组织和管理Robot Framework中的自定义关键字,使其更加灵活和易于维护。

在init.py文件中,确保正确导入自定义关键字所在的模块,确保文件路径的正确性