跳到主要内容

zhiyoufy-python概述

zhiyoufy-python是开发worker的基础模块,它的本身组成也包括了设计中worker应该有的一些部分, 下面对主要组成进行介绍。

GlobalLibraryBase

这个是一个全局单例库,用于完成框架的初始化工作,然后持有一些全局共享的数据,比如

  • config_inst: 配置文件的解析
  • step_vars_map: 不同测试步骤间共享数据的map

当使用robot framework触发时通过在资源文件中指定创建,比如

*** Settings ***
Library xxxx.xxx.GlobalLibrary ${global_library_config} WITH NAME GlobalLibrary

当在本地调试时,在代码中直接创建,比如

    GlobalLibraryBase.g_global_library_base = None
GlobalLibrary.g_global_library = None
GlobalLibrary.GlobalLibrary("config/zhiyoufy_test/robot.conf")

TestDynamicFlowBase

一个case是通过在json文件中描述各个操作步骤来实现的,不同的操作步骤及配置会 产生不同的case,这个是基础支持类

它提供的主要功能包括

添加需要的handler

每个handler可以处理一部分测试步骤,最终的worker可以按需加载对应的handler

    def add_handler(self, handler):
if handler.type_prefix in self.handler_map:
raise Exception("%s is already registered" % handler.type_prefix)

self.handler_map[handler.type_prefix] = handler
handler.setup(self)

模板的渲染

case描述文件中有一些动态部分,比如某个步骤是否需要ignore,某个变量的值等,这里负责 通过解析的config及配置的override_map来渲染

        config_path = ConfigUtil.render_config_if_needed(test_config, override_map=override_map)

case运行

依次读取render之后的case描述模板中的test case step,根据type选择相应的handler进行处理

    def run(self, test_config, override_map=None):

self.process_datas_node()

def process_node(self, node_datas, log_prefix):

self.process_command(data)

TestDynamicFlowContext

context数据,主要提供handler对应client和client_factory的保存

    def add_lib_client_factory(self, lib_client_name, lib_client_factory):
self.lib_client_factory_map[lib_client_name] = lib_client_factory

def get_lib_client(self, lib_client_name):
if lib_client_name in self.lib_client_map:
return self.lib_client_map[lib_client_name]
if lib_client_name in self.lib_client_factory_map:
self.lib_client_map[lib_client_name] = self.lib_client_factory_map[lib_client_name]()
return self.lib_client_map[lib_client_name]

handler

handler用于处理case描述文件中的具体步骤,一般一个被测产品封装一个handler,比如针对zhiyoufy就有 封装DynamicFlowZhiyoufyClient

handler需要挂载到TestDynamicFlowBase中

        self.add_handler(DynamicFlowZhiyoufyClient())

handler的具体处理通常由一个对应的client来处理,这两个的区别是,client是对对应功能的 封装,不光面向测试,也面向一般的自动化使用,而handler里会按需对步骤的结果进行效验,比如

    def process_type_zhiyoufy_config_single_get_single_by_name(self, data):
zhiyoufy_client = self.zhiyoufy_client

target_config_single = zhiyoufy_client.config_single_client.config_single_get_single_by_name(data)

if "expected_rsp" in data:
is_expected = CheckUtil.check_dict_expected(
data["expected_rsp"], data["expected_rsp"], target_config_single)

if not is_expected:
self.robot_logger.error(f"{self.log_prefix}: Not match the expected rsp! \n"
f" Expected {data['expected_rsp']}\n Real {target_config_single}")
raise Exception(f"zhiyoufy_config_single_get_single_by_name: Not match the expected rsp!")

handler根据测试step type,选择正确的client执行测试请求,并对client返回的测试请求响应进行正确性验证

        elif data['type'] == 'zhiyoufy_base_login':
self.process_type_zhiyoufy_base_login(data)
elif data['type'] == 'zhiyoufy_base_logout':
self.process_type_zhiyoufy_base_logout(data)

为了减少耦合,handler之间各自独立,一个handler只使用从属于它的client, 不跨界使用其它handler的client,如果不同handler有数据共享需求,可通过 GlobalLibraryBase中的全局step_vars_map实现。

client

client是类似sdk client的对目标产品的client侧封装,具体实现上为了降低复杂度,也为了 维持与后端的一致,一般都是由一个parent client和一组child clients组成

parent client

parent client包含child clients,一些基本功能比如login、logout可能也会直接在parent实现

        self.user_client = ZhiyoufyClientUser(parent_client=self)
self.environment_client = ZhiyoufyClientEnvironment(parent_client=self)
self.config_single_client = ZhiyoufyClientConfigSingle(parent_client=self)
self.config_collection_client = ZhiyoufyClientConfigCollection(parent_client=self)

bridge

每个child client都会继承自一个bridge基类,bridge基类负责封装各个child client及一些共用的数据,比如

class ZhiyoufyClientBridge(CustomLibraryBridgeBase):

@property
def api_base_url(self):
return self.parent_client.api_base_url

@property
def zhiyoufy_addr(self):
return self.parent_client.zhiyoufy_addr

@property
def user_client(self):
return self.parent_client.user_client

@property
def environment_client(self):
return self.parent_client.environment_client

# pass info between steps, similar to programming variables
def get_step_var(self, step_var_path, raise_exception_if_miss=None):
return self.parent.get_step_var(step_var_path, raise_exception_if_miss)

def set_step_var(self, step_var_path, step_var_value):
self.parent.set_step_var(step_var_path, step_var_value)

child client

根据业务功能或者接口定义划分不同的child client

比如ZhiyoufyClientEnvironment就被封装用来处理environment的增删改查,对应的服务端后端其实 也有对应的模块,并且有统一的url前缀{self.zhiyoufy_addr}{self.api_base_url}/environment

  • client的实现采用类似于SDK的开发方式,各个client只做具体的事,不验证响应结果(当用于测试目的时由调用它的handler进行响应结果验证)
  • 各个child client之间可以通过Global step_var_map实现信息传递
  • 根据测试需求,child clients之间可以有交互,可以通过bridge基类调用另一个child client的函数