Unittest二次开发实战

news2024/11/25 9:46:06

目录

  前言

  unittest.TestResult类简介

  TestResult类定制目标

  实现步骤

  测试结果summary格式规划

  单个用例结果格式规划

  用例tags和level的实现

  根据测试方法对象获取用例代码

  单个用例结果类的实现

  TestResult属性及初始化方法

  测试开始和测试结束

  用例开始和用例结束

  1. 重写恢复输出流方法

  2. 用例开始和结束方法

  用例结果注册

  测试本TestResult类方法

  其他函数和方法

  1. 用例状态列

  2. 获取平台信息

  3. 从异常中提取异常信息方法

  4. 从异常和已知异常中提取失败原因的方法


  前言

  Unittest是Python自带的自动化测试框架,提供了基本的控制结构和模型概念。

  由于Unittest功能较为基础,因此在实际框架实战中往往需要对其功能进行扩充。

  比如:

  ·生成HTML报告

  ·多线程并发(并且报告不混乱)

  ·自动重试出错用例

  ·为用例提供tags标签和level等级等,往往需要我们对Unittest框架进行二次开发和扩展,由于Unittest框架清晰的API,扩展和定制也非常方便。

  unittest.TestResult类简介

  TestResult类一般在TestRunner类中实例化,并穿梭于每个执行的测试套件和测试用例中用于记录结果。

  TestResult对象常用的属性有:

  ·stream:用于输出测试信息的IO流,一般是终端或文本文件。

  ·descriptions:描述信息。

  ·verbosity:显示详细级别。

  ·buffer:默认为False,用例中的print信息立即输出,buffer为True时将用例中的print信息统一收集并集中输出。

  ·tb_locals: 在报错异常信息中显示用例中的局部变量(即tackback_locals)。

  ·failfast:默认为False, 用例失败后继续运行,为True时,任何一条用例失败时立即停止。

  ·_mirrorOutput:是否重定向输出流状态标志unittest.TestResult类提供了以下几种方法:

      -运行开始/结束

        startTestRun: 执行开始时调用,参考unittest.TextTestRunner中的run方法。

        stopTestRun: 所有用例执行结束后调用

        startTest:单个用例执行开始时调用,参考unittest.TestCase类中的run方法。

        stopTest:单个用例执行结束后调用。

      -注册用例结果

        addSuccess:单个用例执行成功时调用,来注册结果,默认为空。

        addFailure:用例失败时在stopTest前调用。

        addError:用例异常时在stopTest前调用。

        addSkip:用例跳过时在stopTest前调用。

        addExpectedFailure:用例期望失败时在stopTest前调用。

        addUnexpectedSuccess:用例非期望成功时在stopTest前调用。

      -重定向和恢复系统输出流

        _setupStdout:重定向输出流,默认self.buffer为True时生效

        _restoreStdout:恢复系统输出流

  用例失败Failure和用例异常Error的区别:

  用例中的断言错误(期望结果和实际结果不一致)引发的AssertionError异常被视为用例失败,其他异常视为用例异常Error。

  ExpectedFailure和UnexpectedSuccess: 期望失败指我们期望这条用例执行失败,即用例失败了才是符合预期的,而没有失败即UnexpectedSuccess,这是一种反向用例,如果失败了其实是通过,而成功了反而是失败。

  TestResult类定制目标

  1. 在result中增加整体的运行开始时间start_at,持续时间duration和每条用例的开始时间,执行时间

  2. 存储用例中的print信息及异常信息,以供生成HTML使用

  3. 为已知异常提供失败原因

  4. 提供结构化和可序列化的summary和详情数据

  5. 探测每个用例code,以为审视用例代码提供方便

  6. 增加运行平台platform信息和运行时的环境变量信息

  7. 将print信息改为使用log记录,增加日志时间,方便追溯。

  8. 提供用例的更多的信息,如tags,level, id, 描述等信息。

  实现步骤

  测试结果summary格式规划

  测试结果result类提供一个summary属性,格式如下(参考了httprunner的summary格式):

name: result结果名称
  success: 整个测试结果是否成功
  stat: # 结果统计信息
    testsRun: 总运行数
    successes: 成功数
    failures: 失败数
    errors: 异常数
    skipped: 跳过的用例数
    expectedFailures: 期望失败数
    unexpectedSuccesses: 非期望成功数
  time:
    start_at: 整个测试开始时间(时间戳)
    end_at: 增高测试结束时间(时间戳)
    duration: 整个测试执行耗时(秒)
  platform:
    platform: 执行平台信息
    system: 执行操作系统信息
    python_version: Python版本信息
    # env: 环境变量信息(信息中可能包含账号等敏感信息)
  details:  # 用例结果详情
    - ... # 单个用例结果

  单个用例结果格式规划

# 执行前可获取的信息
  name: 用例名称或用例方法名
  id: 用例完整路径(模块-类-用例方法名)
  decritpion: 用例描述(用例方法docstring第一行)
  doc: 用例方法完整docstring
  module_name: 用例模块名
  class_name: 用例类名
  class_id: 用例类路径(模块-类)
  class_doc: 用例类docstring描述
  tags: 用例标签
  level: 用例等级
  code: 用例代码
  # 执行后可获取的信息
  time:
    start_at: 用例执行开始时间
    end_at: 用例结束时间
    duration: 用例执行持续时间
  status: 用例执行状态success/fail/error/skipped/xfail/xpass
  output: 用例中的print输出信息
  exc_info: 用例异常追溯信息
  reason: 用例跳过,失败,出错的原因

  读者也可以根据自己的需要添加其他额外的信息,如timeout用例超时时间配置,order用例执行顺序,images用例中的截图,link用例中的链接等信息。

  以上的tags和level通过在用例方法的docstring中注入"tag:smoke"及"level:1"等样式为用例添加标签和等级,然后配合定制的loader用例加载器去收集指定标签或等级的用例,下节会详细讲解。

  用例tags和level的实现

  每个框架都会有自己约定格式,这里我采用在docstring注入特定格式描述的方式为用例添加tags和level信息,用例格式如下。

import unittest
  class TestDemo(unittest.TestCase):
      def test_a(self):
          """测试a
          tag:smoke
          tag:demo
          level:1
          """
          print('测试a')

  对于每个用例对象,可以使用test._testMethodDoc来获取其完整的docstring字符串,然后通过正则匹配来匹配出用例的tags列表和level等级,实现方法如下。

import re
  TAG_PARTTEN = 'tag:(\w+)'
  LEVEL_PARTTEN = 'level:(\d+)'
  def get_case_tags(case: unittest.TestCase) -> list:
      """从用例方法的docstring中匹配出指定格式的tags"""
      case_tags = None
      case_doc = case._testMethodDoc
      if case_doc and 'tag' in case_doc:
          pattern = re.compile(TAG_PARTTEN)
          case_tags = re.findall(pattern, case_doc)
      return case_tags
  def get_case_level(case: unittest.TestCase):
      """从用例方法的docstring中匹配出指定格式的level"""
      case_doc = case._testMethodDoc
      case_level = None  # todo 默认level
      if case_doc:
          pattern = re.compile(LEVEL_PARTTEN)
          levels = re.findall(pattern, case_doc)
          if levels:
              case_level = levels[0]
              try:
                  case_level = int(case_level)
              except:
                  raise ValueError(f'用例中level设置:{case_level} 应为整数格式')
      return case_level

  根据测试方法对象获取用例代码

def inspect_code(test):
      test_method = getattr(test.__class__, test._testMethodName)
      try:
          code = inspect.getsource(test_method)
      except Exception as ex:
          log.exception(ex)
          code = ''
      return code

  单个用例结果类的实现

  由于单个用例结果信息较多,我们可以在整个TestResult类中使用一个嵌套字典格式存储,也可以单独定制一个用例结果类,参考如下。

class TestCaseResult(object):
      """用例测试结果"""
      def __init__(self, test: unittest.case.TestCase, name=None):  
          self.test = test  # 测试用例对象
          self.name = name or test._testMethodName  # 支持传入用例别名,unittest.TestCase自带属性方法
          self.id = test.id()  # 用例完整路径,unittest.TestCase自带方法
          self.description = test.shortDescription()  # 用例简要描述,unittest.TestCase自带方法
          self.doc = test._testMethodDoc  # 用例docstring,,unittest.TestCase自带属性方法
          self.module_name = test.__module__  # 用例所在模块名
          self.class_name = test.__class__.__name__  # 用例所在类名
          self.class_id = f'{test.__module__}.{test.__class__.__name__}'  # 用例所在类完整路径
          self.class_doc = test.__class__.__doc__  # 用例所在类docstring描述
          self.tags = get_case_tags(test)   # 获取用例tags
          self.level = get_case_level(test)  # 获取用例level等级
          self.code = inspect_code(test)   # 获取用例源代码
          # 用例执后更新的信息
          self.start_at = None    # 用例开始时间
          self.end_at = None  # 用例结束时间
          self.duration = None  # 用例执行持续时间
          self.status = None  # 用例测试状态
          self.output = None  # 用例内的print信息
          self.exc_info = None  # 用例异常信息
          self.reason = None  # 跳过,失败,出错原因
      @property
      def data(self):  # 组合字典格式的用例结果数据
          data = dict(
              name=self.name,
              id=self.id,
              description=self.description,
              status=self.status,
              tags=self.tags,
              level=self.level,
              time=dict(  # 聚合时间信息
                  start_at=self.start_at,
                  end_at=self.end_at,
                  duration=self.duration
              ),
              class_name=self.class_name,
              class_doc=self.class_doc,
              module_name=self.module_name,
              code=self.code,
              output=self.output,
              exc_info=self.exc_info,
              reason=self.reason,
          )
          return data

  TestResult属性及初始化方法

  根据上面对测试结果summary格式的规划,我们继承unittest.TestResult类来定制我们的测试结果类。

import unittest
  class TestResult(unittest.TestResult):
      """定制的测试结果类,补充用例运行时间等更多的执行信息"""
      def __init__(self,stream=None,descriptions=None,verbosity=None):
          super().__init__(stream, descriptions, verbosity)  # 调用父类方法,继承父类的初始化属性,然后再进行扩充
           # 对父类的默认熟悉做部分修改
           self.testcase_results = []  # 所有用例测试结果对象(TestCaseResult对象)列表
           self.successes = []  # 成功用例对象列表,万一用得着呢
           self.verbosity = verbosity or 1  # 设置默认verbosity为1
           self.buffer = True  # 在本定制方法中强制使用self.buffer=True,缓存用例输出
          
          self.name = None  # 提供通过修改result对象的name属性为结果提供名称描述 
          self.start_at = None
          self.end_at = None
          self.duration = None
          
          # 由于继承的父类属性中存在failures、errors等属性(存放失败和异常的用例列表),此处加以区分
          self.successes_count = 0  # 成功用例数
          self.failures_count = 0  # 失败用例数
          self.errors_count = 0  # 异常用例数
          self.skipped_count = 0  # 跳过用例数
          self.expectedFailures_count = 0  # 期望失败用例数
          self.unexpectedSuccesses_count = 0  # 非期望成功用例数
          
          self.know_exceptions = {}  # 已知异常字典,用于通过异常名来映射失败原因,如
          # self.know_exceptions = {'requests.exceptions.ConnectionError': '请求连接异常'}
          @property
          def summary(self):
          """组装结果概要, details分按运行顺序和按类组织两种结构"""
          data = dict(
              name=self.name,
              success=self.wasSuccessful(),  # 用例是否成功,父类unittest.TestResult自带方法
              stat=dict(
                  testsRun=self.testsRun,
                  successes=self.successes_count,
                  failures=self.failures_count,
                  errors=self.errors_count,
                  skipped=self.skipped_count,
                  expectedFailures=self.expectedFailures_count,
                  unexpectedSuccesses=self.unexpectedSuccesses_count,
              ),
              time=dict(
                  start_at=self.start_at,
                  end_at=self.end_at,
                  duration=self.duration
              ),
              platform=get_platform_info(),
              details=[item.data for item in self.testcase_results]  # 每个测试用例结果对象转为其字典格式的数据
          )
          return data

  测试开始和测试结束

  使用log信息代替原来的print输出到stream流,这里使用的是笔者发布的开源包logz,安装方法为:

 pip install logz

  logz非常方便配置和使用,支持方便的配置,单例,DayRoting,准确的调用追溯以及log到Email等,详细使用方法可参考:https://github.com/hanzhichao/logz。

  TestResult类中的verbosity属性用于控制输出信息的详细等级,unittest.TextTestResult分为0,1,2三级,作者这里也采用3级模式,逻辑稍有不同,这里设计的逻辑如下。

  1、verbosity>1时:输出整个执行开始和结束信息,每个用例除自身print输出外,打印两条开始和结束两条日志,分别显示用例名称描述+执行时间和执行结果+持续时间。

  2、verbosity为1时:不输出整体开始和结束信息,只每天用例输出用例方法名和执行状态一行日志。

  3、verbosity为0时:不输出任何信息,包括错误信息。

  以下为对父类执行开始和执行结束方法的重写。

 import time
  from logz import log  # 需要安装logz
  def time_to_string(timestamp: float) -> str:
      """时间戳转时间字符串,便于日志中更易读""
      time_array = time.localtime(timestamp)
      time_str = time.strftime("%Y-%m-%d %H:%M:%S", time_array)
      return time_str
  class TestResut(unittest.TestResult):
      ...
          def startTestRun(self):
          """整个执行开始"""
          self.start_at = time.time()  # 整个执行的开始时间
          if self.verbosity > 1:
              self._log(f'===== 测试开始, 开始时间: {time_to_string(self.start_at)} =====')
      def stopTestRun(self):
          """整个执行结束"""
          self.end_at = time.time()  # 整个执行的结束时间
          self.duration = self.end_at - self.start_at  # 整个执行的持续
          self.success = self.wasSuccessful()  # 整个执行是否成功
          if self.verbosity > 1:
              self._log(f'===== 测试结束, 持续时间: {self.duration}秒 =====')

  由于父类中的startTestRun和stopTestRun没有任何内容,此处不需要再调用父类的方法。

  原始的unittest.TextTestRunner中对整个执行时间的统计是在result对象外的,此处集成到result对象中,已使result的结果信息更完整。

  用例开始和用例结束

  捕获用例输出信息,在用例中常常会有print信息或出错信息,这里面的信息是直接写到系统标准输出stdout和stderr中的。要捕获并记录这些信息的话,我们需要再执行用例的过程中(从startTest到stopTest)将系统stdout和stderr临时重定向到我们的io流变量中,然后通过get_value()获取其中的字符串。

  可喜的是,父类unittest.TestResult中便提供了重定向和恢复输出的参考方法,我们稍微改动即可。

  1. 重写恢复输出流方法

  由于startTest父类中自动调用_setupOutput方法,并且强制self.buffer为True,因此会自动重定向信息流,无需重写。

  这里去掉了对原始输出流的信息输出,改为return字符串,之后再使用log输出。

def _restoreStdout(self):
          """重写父类的_restoreStdout方法并返回output+error"""
          if self.buffer:
              output = error = ''
              if self._mirrorOutput:
                  output = sys.stdout.getvalue()
                  error = sys.stderr.getvalue()
              # 去掉了对原始输出流的信息输出
              sys.stdout = self._original_stdout
              sys.stderr = self._original_stderr
              self._stdout_buffer.seek(0)
              self._stdout_buffer.truncate()
              self._stderr_buffer.seek(0)
              self._stderr_buffer.truncate()
              return output + error or None  # 改为return字符串,之后再log输出

  2. 用例开始和结束方法

  def startTest(self, test: unittest.case.TestCase):
          """单个用例执行开始"""
          super().startTest(test)  # 调用父类方法
          test.result = TestCaseResult(test)  # 实例化用例结果对象来记录用例结果,并绑定用例的result属性
          self.testcase_results.append(test.result)  # 另外添加到所有的结果列表一份
          test.result.start_at = time.time()  # 记录用例开始时间
       
          if self.verbosity > 1:
              self._log(f'执行用例: {test.result.name}: {test.result.description}, 开始时间: {time_to_string(test.result.start_at)}')
      def stopTest(self, test: unittest.case.TestCase) -> None:
          """单个用例结束"""
          test.result.end_at = time.time()  # 记录用例结束时间
          test.result.duration = test.result.end_at - test.result.start_at   # 记录用例持续时间
          
          # 由于output要从_restoreStdout获取,手动加入父类恢复输出流的方法
          test.result.output = self._restoreStdout()
          self._mirrorOutput = False  # 是否重定向输出流标志

  用例结果注册

def addSuccess(self, test):
          """重写父类方法, 单个用例成功时在stopTest前调用"""
          test.result.status = TestStatus.SUCCESS
          self.successes.append(test)
          self.successes_count += 1
          super().addSuccess(test)
      @failfast
      def addFailure(self, test, err):
          """重写父类方法, 用例失败时在stopTest前调用"""
          test.result.status = TestStatus.FAIL
          test.result.exc_info = self._exc_info_to_string(err, test)
          test.result.reason = self._get_exc_msg(err)
          self.failures_count += 1
          super().addFailure(test, err)
      @failfast
      def addError(self, test, err):
          """重写父类方法, 用例异常时在stopTest前调用"""
          test.result.status = TestStatus.ERROR
          test.result.exc_info = self._exc_info_to_string(err, test)
          test.result.reason = self._get_exc_msg(err)
          self.errors_count += 1
          super().addError(test, err)
      def addSkip(self, test, reason):
          """重写父类方法, 用例跳过时在stopTest前调用"""
          test.result.status = TestStatus.SKIPPED
          test.result.reason = reason
          self.skipped_count += 1
          super().addSkip(test, reason)
      def addExpectedFailure(self, test, err):
          """重写父类方法, 用例期望失败时在stopTest前调用"""
          test.result.status = TestStatus.XFAIL
          test.result.exc_info = self._exc_info_to_string(err, test)
          test.result.reason = self._get_exc_msg(err)
          self.expectedFailures_count += 1
          super().addExpectedFailure(test, err)
      @failfast
      def addUnexpectedSuccess(self, test):
          """重写父类方法, 用例非期望成功时在stopTest前调用"""
          test.result.status = TestStatus.XPASS
          self.expectedFailures_count += 1
          super().addUnexpectedSuccess(test)

  测试本TestResult类方法

 if __name__ == '__main__':
      import unittest
      class TestDemo(unittest.TestCase):  
          def test_a(self):  # 可以添加更多的用例进行测试
              """测试a
              tag:smoke
              tag:demo
              level:1
              """
              print('测试a')
      suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestDemo)
      runner = unittest.TextTestRunner(resultclass=TestResult)  # 使用定制的TestResult类
      result = runner.run(suite)
      print(result.summary)  # 输出result的字典格式数据,建议使用pprint输出,需要安装pprint

  注:由于和作者本人自己使用的TestResult类有所精简和改动,尚未进行更多的测试,如有问题欢迎留言指正。

  其他函数和方法

  1. 用例状态列

  为了方便修改状态名称,(如改成中文),这里使用用例状态类。

class TestStatus(object):
      SUCCESS = 'success'
      FAIL = 'fail'
      ERROR = 'error'
      SKIPPED = 'skipped'
      XFAIL = 'xfail'
      XPASS = 'xpass'

  2. 获取平台信息

 import os
  def get_platform_info():
      """获取执行平台信息"""
      return {
          "platform": platform.platform(),
          "system": platform.system(),
          "python_version": platform.python_version(),
          # "env": dict(os.environ),
      }

  3. 从异常中提取异常信息方法

def _exc_info_to_string(self, err, test):
          """重写父类的转换异常方法, 去掉buffer的输出"""
          exctype, value, tb = err
          while tb and self._is_relevant_tb_level(tb):
              tb = tb.tb_next
          if exctype is test.failureException:
              # Skip assert*() traceback levels
              length = self._count_relevant_tb_levels(tb)
          else:
              length = None
          tb_e = traceback.TracebackException(
              exctype, value, tb, limit=length, capture_locals=self.tb_locals)
          msgLines = list(tb_e.format())
          return ''.join(msgLines)

  4. 从异常和已知异常中提取失败原因的方法

def _get_exc_msg(self, err):
          exctype, value, tb = err
          exc_msg = str(value)
          exc_full_path = f'{exctype.__module__}.{exctype.__name__}'
          if self.know_exceptions and isinstance(self.know_exceptions, dict):
              exc_msg = self.know_exceptions.get(exc_full_path, exc_msg)
          return exc_msg

 作为一位过来人也是希望大家少走一些弯路,在这里我给大家分享一些自动化测试前进之路的必须品,希望能对你带来帮助。(WEB自动化测试、app自动化测试、接口自动化测试、持续集成、自动化测试开发、大厂面试真题、简历模板等等),相信能使你更好的进步!

留【自动化测试】即可【自动化测试交流】:574737577(备注ccc)icon-default.png?t=N5F7http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=hIqEQD5B5ZyLT0S-vFq64p5MCDBc8jJU&authKey=O%2B3T95fjNUNsYxXnPIrOxvkb%2BbuFd1AxuUP5gCbos34AQDjaRG2L6%2Fm9gGakvo94&noverify=0&group_code=574737577

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/666240.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python面向对象编程2-面向过程的银行账号模拟程序 项目2.3 单个账户完整项目版本1

项目总目标:用面向过程思想设计一个简单的银行账号模拟程序。本次将迭代多个程序版本,每个版本都将添加更多功能。虽然这些程序没有达到发布的质量标准,但整个项目的目的是关注于代码如何与一个或多个银行账户的数据进行交互。 分析项目的必…

Windows11 WSL子系统ubuntu22.04 修改hostname

大家都知道以往我们修改 Linux系统的 hostname只要修改 /etc/hostname 这个文件中的名字即可,但是在WSL中修改该文件是无法生效的。 要修改Hostname并使它生效,我们必须修改 /etc/wsl.conf 文件。 编辑配置文件 sudo vi /etc/wsl.conf修改参数 将 ho…

SQL优化--如何定位慢查询?

目录 概述 检测方案 方案一:开源工具 方案二:MySQL自带慢日志 面试回答 大纲 范例 概述 在SQL中,“慢查询”是指执行速度较慢的数据库查询操作。 一般来说聚合查询,多表查询,表数据量过大查询,深度…

埃及极简史

埃及全称为阿拉伯埃及共和国,位于北非东部,领土还包括苏伊士运河以东、亚洲西南端的西奈半岛,埃及既是亚、非之间的陆地交通要冲,也是大西洋于印度洋之间海上航线的捷径,战略位置十分重要。 古埃及是古代四大文明古国之…

龙蜥白皮书精选:Ancert——硬件兼容性验证与守护

文/硬件兼容性 SIG Ancert 是龙蜥操作系统硬件兼容性测试套件,致力于验证硬件设备集成商等厂商发布的整机服务器和各种板卡外设与龙蜥操作系统 不同版本之间的兼容性,推动社区发行版在各种硬件设备上的适配,围绕龙蜥操作系统建立完善的硬件生…

Linux运维监控学习笔记5

监控项和应用集(重点) 监控项(item):监控项是从主机收集的信息。一个监控项是一个独立的子标,代表收集数据或监控的最小的单位。 应用集(applications):代表多个监控项…

手写数字识别Python+TensorFlow+CNN卷积神经网络【完整代码系统】

一、介绍 手写数字识别系统,使用Python语言,基于TensorFlow搭建CNN卷积神经网络算法对数据集进行训练,最后得到模型,并基于FLask搭建网页端界面,基于Pyqt5搭建桌面端可视化界面。 二、效果展示 三、演示视频完整代码…

【面试题】MySQL的面试题-分组后数据的处理

有一张业务表 data busi,字段为 id,业务号 busi no 以及编码 busi code,请写出根据busi code 将 busi no 合并去重的 sal。数据: 要求最后的结果为: 这个问题怎么解决呢? 其实解决这个问题的关键是分组后的数据合并,这里需要使用…

热加载工具spring-boot-devtools,使页面修改不重启服务器可以实时更新选择和创建数据库(谷粒商城)

阿丹&#xff1a; 希望可以通过工具进行来进行代码修改的时候能避免重启服务。来加快代码进度。 在pom.xml中添加spring-boot-devtools依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifact…

FI 创建资产和 子资产 BAPI_FIXEDASSET_OVRTAKE_CREATE

AS01 AS11 对应的BAPI 都是 BAPI_FIXEDASSET_OVRTAKE_CREATE 创建子资产有个标记CREATESUBNUMBER

PV180R1K1T1NMMC德国产派克柱塞泵

PV180R1K1T1NMMC德国产派克柱塞泵 派克柱塞泵的介绍&#xff1a; PARKER柱塞泵根据倾斜元件的不同&#xff0c;有斜盘式和斜轴式两种。斜盘式是斜盘相对回转的缸体有一倾斜角度&#xff0c;而引起柱塞在泵缸中往复运动。传动轴轴线和缸体轴线是一致的。这种结构较简单&#x…

async_await异常捕获

写在前面 不知道大家项目里面是怎么处理 async/await 的异常&#xff0c;我斗胆在我们项目里翻了一下&#xff0c;发现大量使用 try-catch 来处理 async/await 异常。 首先说明一下&#xff0c; try-catch 处理并没有什么问题&#xff0c;我只是觉得这么写代码会有点乱&#x…

如何设计一个高效的分布式日志服务平台

作者 | 百度智能小程序团队 导读 本文首先介绍了分布式服务下日志服务建设的挑战&#xff0c;然后介绍了下业内ELK的通用解决方案及与天眼日志服务的差异性&#xff0c;接下来详细介绍了天眼日志服务平台的整体架构&#xff0c;如何做采集、传输、检索、隔离、清理等机制的&…

自定义element-table列表展示(可设置按钮权限)

<template><!-- 二次封装表格&#xff0c; 仅支持单选 :style"{ height: height }"--><div class"self_table"><el-table:data"tableData"style"width: 100%"v-loading"loading"stripeselection-chang…

苹果手机备份占内存吗 苹果手机备份到电脑怎么操作

苹果手机备份占内存吗&#xff1f;实际上&#xff0c;苹果手机备份并不占用本机内存。在使用苹果手机的过程中&#xff0c;备份是一个必要的操作&#xff0c;可以避免丢失重要的数据或者恢复丢失的数据。但是有些用户可能会担心备份会占用手机的内存&#xff0c;从而影响手机的…

统信UOS系统开发笔记(五):安装QtCreator开发IDE中的中文输入环境Fcitx输入法

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/131302096 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软…

MySQL 日志管理、备份与恢复

目录 一、 MySQL日志管理1.1 日志的分类1.1.1 错误日志1.1.2 通用查询日志1.1.3 二进制日志1.1.4 慢查询日志1.1.5 配置日志 1.2 日志的查询 二、数据库备份的分类2.1 数据备份的重要性2.2 数据库备份的分类2.3 常用的备份方法2.4 MySQL完全备份2.4.1 mysql完全备份2.4.2 mysql…

【FPGA入门】第五篇、按键消抖

目录 第一部分、按键抖动现象 第二部分、消抖思路及代码 1、简单的按键消抖思路 2、实际按键消抖思路 3、实际按键消抖模块代码 第三部分、总结 第一部分、按键抖动现象 只要学习过单片机的都会知道&#xff0c;按键在按下去和松开的那个瞬间都存在抖动&#xff0c;在单片…

玩转AI绘图 电脑配置怎么选?

大家好&#xff0c;我是权知星球&#xff0c;很多小伙伴留言想了解一下AI绘图相关知识&#xff0c;那么&#xff0c;想要玩转AI绘图&#xff0c;电脑配置该怎么选呢&#xff1f; 首先我们了解一下什么叫AI绘图&#xff1f; AI绘图指的是利用人工智能技术实现的自动绘图&#x…

小白到运维工程师自学之路 第三十七集 (mha高可用集群)

一、概述 MHA&#xff08;Master High Availability&#xff09;是一个开源的MySQL高可用性解决方案&#xff0c;它可以自动监测MySQL主节点的状态&#xff0c;并在主节点发生故障时自动将从节点提升为新的主节点&#xff0c;从而实现MySQL的高可用性。MHA集群通常由多个MySQL实…