• RobotFramework学习系列(三)


      前两篇文章讲解了Suite的构造,文件到Robot的数据格式的转化。这篇文章继续讲解

      回到入口函数Robotframework().main()

      8行之前已经讲过了,8行为对suite的配置。9行为重点

     1     def main(self, datasources, **options):
     2         settings = RobotSettings(options)
     3         LOGGER.register_console_logger(**settings.console_logger_config)
     4         LOGGER.info('Settings:
    %s' % unicode(settings))
     5         suite = TestSuiteBuilder(settings['SuiteNames'],
     6                                  settings['WarnOnSkipped'],
     7                                  settings['RunEmptySuite']).build(*datasources)
     8         suite.configure(**settings.suite_config)
     9         result = suite.run(settings)
    10         LOGGER.info("Tests execution ended. Statistics:
    %s"
    11                     % result.suite.stat_message)
    12         if settings.log or settings.report or settings.xunit:
    13             writer = ResultWriter(settings.output if settings.log else result)
    14             writer.write_results(settings.get_rebot_settings())
    15         return result.return_code

      suite.run()是robot unningmodel.py下TestSuite的方法,具体构造已经在上篇文章中简单讲述了

     1     def run(self, settings=None, **options):
     2         with STOP_SIGNAL_MONITOR:
     3             IMPORTER.reset()
     4             pyloggingconf.initialize(settings['LogLevel'])
     5             init_global_variables(settings)
     6             output = Output(settings)
     7             runner = Runner(output, settings)
     8             self.visit(runner)
     9         output.close(runner.result)
    10         return runner.result

       这里出现了with STOP_SIGNAL_MONITOR 这个也算是python中的魔法实现了。这篇文章先讲一下这块,with的原理如下

      1、紧跟with后面的语句被执行后后,对象的__enter__()方法被调用,这个方法的返回值将被赋值给as后面的变量
      2、当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit__()方法

      示例代码和输出结果如下

     1 class Test:
     2     def __enter__(self):
     3         print "__enter__"
     4         return self
     5     def __exit__(self, *exc_info):
     6         print "__exit__"
     7     def output(self, message):
     8         print message
     9 with Test() as test:
    10     test.output('test')
    1 C:Python27python.exe E:/test/testwith.py
    2 __enter__
    3 test
    4 __exit__

      返回来看STOP_SIGNAL_MONITOR这个类

     1 class _StopSignalMonitor(object):
     2 
     3     def __init__(self):
     4         self._signal_count = 0
     5         self._running_keyword = False
     6         self._orig_sigint = None
     7         self._orig_sigterm = None
     8 
     9     def __call__(self, signum, frame):
    10         self._signal_count += 1
    11         LOGGER.info('Received signal: %s.' % signum)
    12         if self._signal_count > 1:
    13             sys.__stderr__.write('Execution forcefully stopped.
    ')
    14             raise SystemExit()
    15         sys.__stderr__.write('Second signal will force exit.
    ')
    16         if self._running_keyword and not sys.platform.startswith('java'):
    17             self._stop_execution_gracefully()
    18 
    19     def _stop_execution_gracefully(self):
    20         raise ExecutionFailed('Execution terminated by signal', exit=True)
    21 
    22     def start(self):
    23         # TODO: Remove start() in favor of __enter__ in RF 2.9. Refactoring
    24         # the whole signal handler at that point would be a good idea.
    25         self.__enter__()
    26 
    27     def __enter__(self):
    28         if signal:
    29             self._orig_sigint = signal.getsignal(signal.SIGINT)
    30             self._orig_sigterm = signal.getsignal(signal.SIGTERM)
    31             for signum in signal.SIGINT, signal.SIGTERM:
    32                 self._register_signal_handler(signum)
    33         return self
    34 
    35     def __exit__(self, *exc_info):
    36         if signal:
    37             signal.signal(signal.SIGINT, self._orig_sigint)
    38             signal.signal(signal.SIGTERM, self._orig_sigterm)
    39 
    40     def _register_signal_handler(self, signum):
    41         try:
    42             signal.signal(signum, self)
    43         except (ValueError, IllegalArgumentException), err:
    44             # ValueError occurs e.g. if Robot doesn't run on main thread.
    45             # IllegalArgumentException is http://bugs.jython.org/issue1729
    46             if currentThread().getName() == 'MainThread':
    47                 self._warn_about_registeration_error(signum, err)
    48 
    49     def _warn_about_registeration_error(self, signum, err):
    50         name, ctrlc = {signal.SIGINT: ('INT', 'or with Ctrl-C '),
    51                        signal.SIGTERM: ('TERM', '')}[signum]
    52         LOGGER.warn('Registering signal %s failed. Stopping execution '
    53                     'gracefully with this signal %sis not possible. '
    54                     'Original error was: %s' % (name, ctrlc, err))
    55 
    56     def start_running_keyword(self, in_teardown):
    57         self._running_keyword = True
    58         if self._signal_count and not in_teardown:
    59             self._stop_execution_gracefully()
    60 
    61     def stop_running_keyword(self):
    62         self._running_keyword = False

      程序开始运行时执行顺序为:

      1、__enter__():

        查看signal是否导入成功,导入成功,则获取一下执行signal.getsignal(),对signal.SIGINT和signal.SIGTERM,这两种信号,一个是Crtl+C触发,一个是进程自身要求中断引起,当程序初始运行时,getsignal返回的都是0

        调用_register_signal_handler 对两种信号进行注册,以备将来捕获。在注册时候,使用了signal.signal(signum, self)。请注意这块,signale的第二个参数为捕获到对应信号后的处理函数,此时把self传进去,也就是说处理函数为self()也就是_StopSignalMonito()这块,一会再讲

        此时由于信号只能在主线程设置,所以又判断了一下,给出了相应的告警

      2、退出

        分为两种,接收到SIGINIT or SIGTERM

        此时会调用_StopSignalMonito()进行信号处理,这块又用到Python的魔法,__call__()

        其中的逻辑是,接到一次信号,判断自身状态,如果测试在跑,则后续不再进行,执行teardown后正常退出;如果再次接到信号,直接调用系统的SystemExit()。也就是说在程序运行过程中,我们要中断测试,需要按两次Ctrl+C

        然后再执行__exit__(),此时又执行了signal.signal,传入的是Stop_SignalMonito的两个变量,在执行__enter__时被初始化,此时应该都是0,也就是singal.SIG_DFL,进程采用默认操作。退出with

        无故障,直接调用__exit__(),和上述接到中断信号调用__exit__()的流程是一样的

  • 相关阅读:
    【MFC初学】
    【递归】【3月周赛1】【Problem B】
    不管ACM是不是屠龙之技
    【贪心+背包】【HDU2546】【饭卡】
    【精度问题】【HDU2899】Strange fuction
    【泛化物品】【HDU1712】【ACboy needs your help】
    【递推】【HDU2585】【hotel】
    【二进制拆分多重背包】【HDU1059】【Dividing】
    【水:最长公共子序列】【HDU1159】【Common Subsequence】
    【递推+矩阵快速幂】【HDU2604】【Queuing】
  • 原文地址:https://www.cnblogs.com/sumoning/p/12525630.html
Copyright © 2020-2023  润新知