moler是帮助构建自动化测试的库

moler的Python项目详细描述


image图像构建状态coverage statusbch complianceCodacy徽章license

目录

  1. moler信息
  2. moler用法示例
  3. API设计推理
  4. 设计的API < > >

    摩尔

    moler(moler name origin)是python库 它为构建自动化测试提供了"砖块"。 所有这些"砖块"都有明确的职责,有相似的api, 遵循相同的构造模式(这样就很容易创建新的结构模式)。

    它们在这里:

    • 命令作为自立对象
      • 允许命令触发和解析封装在单个对象中(降低维护成本)
    • 事件观察者和回调(报警是事件示例)
      • 允许在线反应(不是离线后处理)
    • 在后台运行观察者/命令
      • 允许将测试逻辑分解为并行运行的多个命令
      • 允许处理意外的系统行为(重新启动、警报)
    • 状态机->;断开连接后自动连接
      • 增加框架自动恢复功能,并帮助解决"哪里出了问题"
    • 测试所用设备的所有连接的自动日志记录
      • 通过将日志集中在被测系统的不同部分来减少调查时间

    moler用法示例

    让我们看看莫勒的行动。下面是一个假设的用例:"查找所有python进程的pids":

    αααα1
    • 要获得命令,我们要求设备"给我这样的命令"。
    • 要运行命令,我们只需将其作为函数调用(command object是可调用的)
    • 命令返回的通常是dict或dict列表-易于处理

    上面的代码显示:

        PID: 1817 CMD: /usr/bin/python /usr/share/system-config-printer/applet.py
        PID: 21825 CMD: /usr/bin/python /home/gl/moler/examples/command/unix_ps.py
    

    它怎么知道"我的机器"是什么意思?代码从my_devices.yml配置文件加载定义:

    DEVICES:MyMachine:DEVICE_CLASS:moler.device.unixremote.UnixLocalRebexTestMachine:DEVICE_CLASS:moler.device.unixremote.UnixRemoteCONNECTION_HOPS:UNIX_LOCAL:# from stateUNIX_REMOTE:# to stateexecute_command:ssh# via commandcommand_params:# with paramsexpected_prompt:demo@host:test.rebex.netlogin:demopassword:passwordset_timeout:False# remote doesn't support: export TMOUT

    我们的配置中有远程机器。让我们检查一下是否有"readme.txt"文件 在那台机器上(还有一些关于文件的信息):

    remote_unix=DeviceFactory.get_device(name='RebexTestMachine')# it starts in local shellremote_unix.goto_state(state="UNIX_REMOTE")# make it go to remote shellls_cmd=remote_unix.get_cmd(cmd_name="ls",cmd_params={"options":"-l"})remote_files=ls_cmd()if'readme.txt'inremote_files['files']:print("readme.txt file:")readme_file_info=remote_files['files']['readme.txt']forattrinreadme_file_info:print("  {:<18}: {}".format(attr,readme_file_info[attr]))

    正如您可能注意到的,设备是状态机。状态转换在内部定义 配置文件位于connection\u hops下。请注意,只有配置文件 知道"我需要使用ssh进行远程访问"-客户机代码只是说"转到远程"。 因此,您可以在不更改主代码的情况下交换"How to reach remote"。

    上面的代码显示:

        readme.txt file:
          permissions       : -rw-------
          hard_links_count  : 1
          owner             : demo
          group             : users
          size_raw          : 403
          size_bytes        : 403
          date              : Apr 082014
          name              : readme.txt
    

    并行做多件事怎么样?让我们ping google 在询问test.rebex.net关于readme.txt文件的信息时:

    my_unix=DeviceFactory.get_device(name='MyMachine')host='www.google.com'ping_cmd=my_unix.get_cmd(cmd_name="ping",cmd_params={"destination":host,"options":"-w 6"})remote_unix=DeviceFactory.get_device(name='RebexTestMachine')remote_unix.goto_state(state="UNIX_REMOTE")ls_cmd=remote_unix.get_cmd(cmd_name="ls",cmd_params={"options":"-l"})print("Start pinging {} ...".format(host))ping_cmd.start()# run command in backgroundprint("Let's check readme.txt at {} while pinging {} ...".format(remote_unix.name,host))remote_files=ls_cmd()# foreground "run in the meantime"file_info=remote_files['files']['readme.txt']print("readme.txt file: owner={fi[owner]}, size={fi[size_bytes]}".format(fi=file_info))ping_stats=ping_cmd.await_done(timeout=6)# await background commandprint("ping {}: {}={}, {}={} [{}]".format(host,'packet_loss',ping_stats['packet_loss'],'time_avg',ping_stats['time_avg'],ping_stats['time_unit']))
    Start pinging www.google.com ...
    Let's check readme.txt at RebexTestMachine while pinging www.google.com ...
    readme.txt file: owner=demo, size=403
    ping www.google.com: packet_loss=0, time_avg=35.251 [ms]
    

    除了可调用的命令对象作为"未来"工作(结果承诺)。 您可以在后台启动它,然后等待它完成以获取结果。

    如果我们使用日志相关信息增强配置:

    LOGGER:PATH:./logsDATE_FORMAT:"%H:%M:%S"

    然后上述代码将自动创建molers的主日志(moler.log) 显示所有设备上的活动:

    22:30:19.723 INFO       moler               |More logs in: ./logs
    22:30:19.747 INFO       MyMachine           |Connection to: 'MyMachine' has been opened.
    22:30:19.748 INFO       MyMachine           |Changed state from 'NOT_CONNECTED' into 'UNIX_LOCAL'
    22:30:19.866 INFO       MyMachine           |Event 'moler.events.unix.wait4prompt.Wait4prompt':'[re.compile('^moler_bash#')]' started.
    22:30:19.901 INFO       RebexTestMachine    |Connection to: 'RebexTestMachine' has been opened.
    22:30:19.901 INFO       RebexTestMachine    |Changed state from 'NOT_CONNECTED' into 'UNIX_LOCAL'
    22:30:19.919 INFO       RebexTestMachine    |Event 'moler.events.unix.wait4prompt.Wait4prompt':'[re.compile('demo@')]' started.
    22:30:19.920 INFO       RebexTestMachine    |Event 'moler.events.unix.wait4prompt.Wait4prompt':'[re.compile('^moler_bash#')]' started.
    22:30:19.921 INFO       RebexTestMachine    |Command 'moler.cmd.unix.ssh.Ssh':'TERM=xterm-mono ssh -l demo test.rebex.net' started.
    22:30:19.921 INFO       RebexTestMachine    |TERM=xterm-mono ssh -l demo test.rebex.net
    22:30:20.763 INFO       RebexTestMachine    |*********
    22:30:20.909 INFO       RebexTestMachine    |Changed state from 'UNIX_LOCAL' into 'UNIX_REMOTE'
    22:30:20.917 INFO       RebexTestMachine    |Command 'moler.cmd.unix.ssh.Ssh' finished.
    22:30:20.919 INFO       MyMachine           |Command 'moler.cmd.unix.ping.Ping':'ping www.google.com -w 6' started.
    22:30:20.920 INFO       MyMachine           |ping www.google.com -w 6
    22:30:20.920 INFO       RebexTestMachine    |Command 'moler.cmd.unix.ls.Ls':'ls -l' started.
    22:30:20.922 INFO       RebexTestMachine    |ls -l
    22:30:20.985 INFO       RebexTestMachine    |Command 'moler.cmd.unix.ls.Ls' finished.
    22:30:26.968 INFO       MyMachine           |Command 'moler.cmd.unix.ping.Ping' finished.
    22:30:26.992 INFO       RebexTestMachine    |Event 'moler.events.unix.wait4prompt.Wait4prompt': '[re.compile('^moler_bash#')]' finished.
    22:30:27.011 INFO       RebexTestMachine    |Event 'moler.events.unix.wait4prompt.Wait4prompt': '[re.compile('demo@')]' finished.
    22:30:27.032 INFO       MyMachine           |Event 'moler.events.unix.wait4prompt.Wait4prompt': '[re.compile('^moler_bash#')]' finished.
    

    正如您可能注意到的,主日志从高级视图-数据显示代码进度 连接时不可见,只显示设备上运行的命令的活动。

    如果您想详细了解每台设备上发生了什么,请将其保存在设备日志中。 moler为每个设备创建日志 moler.rebextestmachine.log

    frommoler.configimportload_configfrommoler.device.deviceimportDeviceFactoryload_config(config='my_devices.yml')# description of available devicesmy_unix=DeviceFactory.get_device(name='MyMachine')# take specific device out of available onesps_cmd=my_unix.get_cmd(cmd_name="ps",# take command of that devicecmd_params={"options":"-ef"})processes_info=ps_cmd()# run the command, it returns resultforproc_infoinprocesses_info:if'python'inproc_info['CMD']:print("PID: {info[PID]} CMD: {info[CMD]}".format(info=proc_info))
    0

    以及moler.mymachine.log

    frommoler.configimportload_configfrommoler.device.deviceimportDeviceFactoryload_config(config='my_devices.yml')# description of available devicesmy_unix=DeviceFactory.get_device(name='MyMachine')# take specific device out of available onesps_cmd=my_unix.get_cmd(cmd_name="ps",# take command of that devicecmd_params={"options":"-ef"})processes_info=ps_cmd()# run the command, it returns resultforproc_infoinprocesses_info:if'python'inproc_info['CMD']:print("PID: {info[PID]} CMD: {info[CMD]}".format(info=proc_info))
    1

    前面的例子要求设备创建命令。我们也可以自己创建命令 连接到操作:

    frommoler.configimportload_configfrommoler.device.deviceimportDeviceFactoryload_config(config='my_devices.yml')# description of available devicesmy_unix=DeviceFactory.get_device(name='MyMachine')# take specific device out of available onesps_cmd=my_unix.get_cmd(cmd_name="ps",# take command of that devicecmd_params={"options":"-ef"})processes_info=ps_cmd()# run the command, it returns resultforproc_infoinprocesses_info:if'python'inproc_info['CMD']:print("PID: {info[PID]} CMD: {info[CMD]}".format(info=proc_info))
    2

    请注意,连接是上下文管理器执行打开/关闭操作。

    frommoler.configimportload_configfrommoler.device.deviceimportDeviceFactoryload_config(config='my_devices.yml')# description of available devicesmy_unix=DeviceFactory.get_device(name='MyMachine')# take specific device out of available onesps_cmd=my_unix.get_cmd(cmd_name="ps",# take command of that devicecmd_params={"options":"-ef"})processes_info=ps_cmd()# run the command, it returns resultforproc_infoinprocesses_info:if'python'inproc_info['CMD']:print("PID: {info[PID]} CMD: {info[CMD]}".format(info=proc_info))
    3

    重复使用自由

    库可以让您自由地重用哪个部分。我们是"只拿你需要的东西"的粉丝。

    • 您可以使用配置文件或通过python调用进行配置。

      frommoler.configimportload_configfrommoler.device.deviceimportDeviceFactoryload_config(config='my_devices.yml')# description of available devicesmy_unix=DeviceFactory.get_device(name='MyMachine')# take specific device out of available onesps_cmd=my_unix.get_cmd(cmd_name="ps",# take command of that devicecmd_params={"options":"-ef"})processes_info=ps_cmd()# run the command, it returns resultforproc_infoinprocesses_info:if'python'inproc_info['CMD']:print("PID: {info[PID]} CMD: {info[CMD]}".format(info=proc_info))
      4
    • 您可以手动使用设备或创建命令

    • 您可以自己建立连接:

      frommoler.configimportload_configfrommoler.device.deviceimportDeviceFactoryload_config(config='my_devices.yml')# description of available devicesmy_unix=DeviceFactory.get_device(name='MyMachine')# take specific device out of available onesps_cmd=my_unix.get_cmd(cmd_name="ps",# take command of that devicecmd_params={"options":"-ef"})processes_info=ps_cmd()# run the command, it returns resultforproc_infoinprocesses_info:if'python'inproc_info['CMD']:print("PID: {info[PID]} CMD: {info[CMD]}".format(info=proc_info))
      5
    • 您甚至可以安装自己的实现来代替每个连接类型的默认实现

    API设计推理

    命令的主要目标是它的使用简单:只需运行它并返回结果即可。

    命令对调用方隐藏:

    • 如何实现"运行"
    • 如何获取要分析的输出数据
    • 它如何解析数据

    命令显示给调用方:

    • 启动/停止或等待其完成的API
    • 查询其结果或结果就绪性的api

    命令的作用是期货和承诺

    在开始之后,我们等待它的结果,它被解析出通常作为dict提供的命令输出。 运行该命令并分析其输出可能需要一些时间,因此直到该点结果计算尚未完成。

    作为未来的命令

    • 它通过连接在设备/shell上启动一些命令 (当未来函数开始执行时)
    • 它解析通过这种连接传入的数据 (未来的功能正在处理)
    • 它存储解析的结果 (未来函数在计算结果中得出结论)
    • 它提供了返回结果的方法 (正如future函数通过"return"或"yield"语句所做的那样)
    • 结果还没准备好"刚刚"调用命令 (与功能相比,它是未来的)

    所以命令应该有未来的api。

    引自卢克·斯内林格的《专业蟒蛇》:

    < Buff行情>

    未来是一个独立的对象。它独立于正在运行的实际函数。 它只存储状态和结果信息。

    命令的不同之处在于两者都是:

    • 类似于执行计算的对象的函数
    • 存储计算结果的类似未来的对象。

    命令与连接观察员

    命令只是连接观察员的"活动版本"。

    连接观察者是被动的,因为它只是观察一些数据的连接; 可能只是异步出现的数据(警报、重新启动或任何您想要的)。 这里的意图是责任划分:一个观察者在寻找警报, 另一个用于重新启动。

    命令是活动的,因为它在连接时会主动触发一些输出 通过该连接发送命令字符串。所以,它激活了一些动作 在连接后面的设备上。这个动作在设备术语中是"命令"。 就像bash控制台/设备上的ping。它产生"命令"输出。 这个输出是moler作为连接观察者的命令所寻找的。

    最著名的python的未来

    <表><广告>APIconcurrent.futures.future异步。未来< /广告><正文>存储结果 :白色复选标记:设置结果():白色复选标记:设置结果()结果检索 :白色复选标记:result():白色复选标记:result()存储失败原因 :白色复选标记:设置异常():白色复选标记:设置异常()故障原因检索 :白色复选标记:exception():白色复选标记:exception()停止 :白色复选标记:cancel():白色复选标记:cancel()检查是否停止 :白色复选标记:已取消():白色复选标记:已取消()检查是否正在运行:白色复选标记:running():没有输入符号:(但是abstractEventLoop.running())检查是否完成:白色复选标记:done():白色复选标记:done()订阅完成:白色复选标记:add\u done\u callback():白色复选标记:add\u done\u callback()取消订阅完成:无输入符号::白色复选标记:删除已完成的回调函数

    启动可调用以"作为未来"运行是由未来对象外部的实体完成的

    <表><广告><> API concurrent.futures
    通过执行器对象(线程/进程)启动 异步
    通过模块LVL功能或EV回路启动 < /广告><正文>开始可调用提交(fn,*args,**kwargs)
    可调用的计划执行为
    fn(*args**kwargs)->;未来确保未来(coro_或_future)->;任务
    future=运行协同程序线程安全(coro,循环)在数据迭代器上启动相同的可调用
    映射(fn,*iterables,超时)->;迭代器join_future=asyncio.gather(*map(f,iterable))
    循环。运行直至完成(join_future)

    等待未来的完成是由未来对象外部的实体完成的

    <表><广告><> API 并发.未来
    等待模块级功能 异步
    等待模块LVL功能或EV循环 < /广告><正文>等待完成完成,不完成=等待(未来,超时)->;未来完成,未完成=等待等待等待(未来)
    结果=等待收集(未来)
    结果=等待未来
    结果=从未来获得收益
    结果=等待协程
    结果=从协程获得收益
    结果=从等待获得收益(未来,超时)
    循环。运行直至完成(未来)->;阻塞运行完成时进行处理 对于"完成"状态(期货,超时)->;期货对于"完成"状态(期货,超时)->;期货

    命令的基本差异

    与concurrent.futures和asyncio相反,我们不希望命令由某个外部实体运行。 为了使用简单,我们希望它是自执行的。 我们想接受命令,然后对它说:

    • "运行"或"后台运行"
    • 而不是"嗨,外部运行程序,你能为我运行/运行后台命令吗"

    设计API

    1. 创建命令对象
    2. < > >
      frommoler.configimportload_configfrommoler.device.deviceimportDeviceFactoryload_config(config='my_devices.yml')# description of available devicesmy_unix=DeviceFactory.get_device(name='MyMachine')# take specific device out of available onesps_cmd=my_unix.get_cmd(cmd_name="ps",# take command of that devicecmd_params={"options":"-ef"})processes_info=ps_cmd()# run the command, it returns resultforproc_infoinprocesses_info:if'python'inproc_info['CMD']:print("PID: {info[PID]} CMD: {info[CMD]}".format(info=proc_info))
      6
      1. 同步运行/blocking并一次性获得结果的行为类似于函数调用,因为命令是可调用的。
      2. < > >

        run as callable具有很大的优势,因为它非常适合python生态系统。

        frommoler.configimportload_configfrommoler.device.deviceimportDeviceFactoryload_config(config='my_devices.yml')# description of available devicesmy_unix=DeviceFactory.get_device(name='MyMachine')# take specific device out of available onesps_cmd=my_unix.get_cmd(cmd_name="ps",# take command of that devicecmd_params={"options":"-ef"})processes_info=ps_cmd()# run the command, it returns resultforproc_infoinprocesses_info:if'python'inproc_info['CMD']:print("PID: {info[PID]} CMD: {info[CMD]}".format(info=proc_info))
        7

        功能示例:

        frommoler.configimportload_configfrommoler.device.deviceimportDeviceFactoryload_config(config='my_devices.yml')# description of available devicesmy_unix=DeviceFactory.get_device(name='MyMachine')# take specific device out of available onesps_cmd=my_unix.get_cmd(cmd_name="ps",# take command of that devicecmd_params={"options":"-ef"})processes_info=ps_cmd()# run the command, it returns resultforproc_infoinprocesses_info:if'python'inproc_info['CMD']:print("PID: {info[PID]} CMD: {info[CMD]}".format(info=proc_info))
        8
        1. 异步/非阻塞运行
        2. < > >
          frommoler.configimportload_configfrommoler.device.deviceimportDeviceFactoryload_config(config='my_devices.yml')# description of available devicesmy_unix=DeviceFactory.get_device(name='MyMachine')# take specific device out of available onesps_cmd=my_unix.get_cmd(cmd_name="ps",# take command of that devicecmd_params={"options":"-ef"})processes_info=ps_cmd()# run the command, it returns resultforproc_infoinprocesses_info:if'python'inproc_info['CMD']:print("PID: {info[PID]} CMD: {info[CMD]}".format(info=proc_info))
          9
          1. 从背景切换到前景
          2. < > >

            异步:变量看起来像:

                PID: 1817 CMD: /usr/bin/python /usr/share/system-config-printer/applet.py
                PID: 21825 CMD: /usr/bin/python /home/gl/moler/examples/command/unix_ps.py
            
            0

            并且并发。期货变量看起来像:

                PID: 1817 CMD: /usr/bin/python /usr/share/system-config-printer/applet.py
                PID: 21825 CMD: /usr/bin/python /home/gl/moler/examples/command/unix_ps.py
            
            1

            moler的api映射到上述众所周知的api

                PID: 1817 CMD: /usr/bin/python /usr/share/system-config-printer/applet.py
                PID: 21825 CMD: /usr/bin/python /home/gl/moler/examples/command/unix_ps.py
            
            2
            • 命令"hi command,这就是我想要你做的"(上面的api说"hi you there,这就是我想要你用命令做的事情")是"内部的"
            • 它直接(python的禅)显示了我们在等待什么
            • timeout是必需的参数(而不是concurrent.futures中的参数),因为我们不希望命令无休止地执行(用户必须知道等待命令完成的最坏情况超时是什么)

            欢迎加入QQ群-->: 979659372 Python中文网_新手群

            推荐PyPI第三方库


热门话题
CentOS上的java Spring Boot简易应用程序需要很长时间才能启动   java如何检查字符串值是否等于null?   收集器中的java映射值。分组方式()   java需要支持Azure AD B2C webapp集成   java如何加入线程以停止它?   java如何使用意图传递类的对象?   java如何在战争环境中发现CDI生产者?   多模块项目中java奇怪的编译器行为   java如何在web应用程序中管理密码?   java从http服务器、filehandler中删除冗余代码   java使用反射来获取泛型类的字段   java Spring MVC/Hibernate/MySQL 400错误请求错误   给定正整数a的java幂为3   在Java中将元素拆分为不同数量的列表?   java展开折叠窗格