车载测试之python调用CANoe

159 阅读5分钟

  文章转载链接www.51testing.com/html/60/n-7…

  Canoe主要用来做车载测试的,想了解Canoe的可以自行查找,这篇主要是用于在我们自动化测试中,我们使用python调用canoe的各种功能,如设置系统环境变量,启动测量等等

  首先我们要理解python调用canoe底层是因为Vector公司开放了一些com口,python主要是调用这些com口来实现的,具体有哪些可以打开canoe软件点击右上角问号帮助文档住查看

  代码如下

  import os

  import time

  import msvcrt

  from win32com.client import *

  from win32com.client.connect import *

  def DoEvents():

      pythoncom.PumpWaitingMessages()

      time.sleep(.1)

  def DoEventsUntil(cond):

      while not cond():

          DoEvents()

  # Vector Canoe Class

  class CANoe:

      Started = False

      Stopped = False

      ConfigPath = ""

   

      def __init__(self, visible=True):

          """

          产生一个canoe的com对象,启动了canoe软件,但是未加载任何工程

          :param visible: 其实可以设置canoe对于cfg文件是否保存

          """

          self.application = None

          self.application = DispatchEx("CANoe.Application")

          # self.application.Versible = visible

          self.ver = self.application.Version

          print('Loaded CANoe version ',

                self.ver.major, '.',

                self.ver.minor, '.',

                self.ver.Build, '...')

          # 这里是可以获取到canoe工程是否在启动,这个数值是True或者False

          self.Measurement = self.application.Measurement.Running

   

      def open_cfg(self, cfg_path_file):

          """

          加载cfg工程文件

          :param cfg_path_file:cfg文件的路径,这是是canoe加载cfg文件成功

          :return:

          """

          cfg_path_file = os.path.abspath(cfg_path_file)

          self.ConfigPath = cfg_path_file

          if (self.application != None):

              if os.path.isfile(cfg_path_file) and (os.path.splitext(cfg_path_file)[1] == ".cfg"):

                  self.application.Open(cfg_path_file)

                  print("opening..." + cfg_path_file)

              else:

                  raise RuntimeError("Can't find CANoe cfg file")

          else:

              raise RuntimeError("CANoe Application is missing,unable to open simulation")

   

      def close_cfg(self):

          """

          退出canoe

          :return:

          """

          if (self.application != None):

              print("close cfg ...")

              # self.stop_Measurement()

              self.application.Quit()

              self.application = None

   

      def start_measurement(self):

          """

          启动测量

          :return:

          """

          retry = 0

          retry_counter = 5

          # try to establish measurement within 5s timeout

          while not self.application.Measurement.Running and (retry < retry_counter):

              self.application.Measurement.Start()

              time.sleep(1)

              retry += 1

          if (retry == retry_counter):

              raise RuntimeWarning("CANoe start measuremet failed, Please Check Connection!")

   

      def stop_measurement(self):

          """

          停止测量

          :return:

          """

          if self.application.Measurement.Running:

              self.application.Measurement.Stop()

          else:

              pass

   

      def get_sigval(self, channel_num, msg_name, sig_name, bus_type="CAN"):

          """

          获取信号的值

          :param channel_num:

          :param msg_name:

          :param sig_name:

          :param bus_type:

          :return:

          """

          if (self.application != None):

              result = self.application.GetBus(bus_type).GetSignal(channel_num, msg_name, sig_name)

              return result.Value

          else:

              raise RuntimeError("CANoe is not open,unable to GetVariable")

   

      def set_sigval(self, channel_num, msg_name, sig_name, bus_type, setValue):

          """

          设置信号的值

          :param channel_num:

          :param msg_name:

          :param sig_name:

          :param bus_type:

          :param setValue:

          :return:

          """

          if (self.application != None):

              result = self.application.GetBus(bus_type).GetSignal(channel_num, msg_name, sig_name)

              result.Value = setValue

          else:

              raise RuntimeError("CANoe is not open,unable to GetVariable")

   

      def get_EnvVar(self, var):

          if (self.application != None):

              result = self.application.Environment.GetVariable(var)

              return result.Value

          else:

              raise RuntimeError("CANoe is not open,unable to GetVariable")

   

      def set_EnvVar(self, var, value):

          result = None

          if (self.application != None):

              # set the environment varible

              result = self.application.Environment.GetVariable(var)

              result.Value = value

              checker = self.get_EnvVar(var)

              # check the environment varible is set properly?

              while (checker != value):

                  checker = self.get_EnvVar(var)

          else:

              raise RuntimeError("CANoe is not open,unable to SetVariable")

   

      def get_system_variable_value(self, sys_var_name):

          """获取系统环境变量的值

          参数:

              sys_var_name (str): "sys_var_demo::speed"

          Returns:

              返回该系统变量的值

          """

          namespace = '::'.join(sys_var_name.split('::')[:-1])

          variable_name = sys_var_name.split('::')[-1]

          return_value = None

          try:

              namespace_com_object = self.application.System.Namespaces(namespace)

              variable_com_object = namespace_com_object.Variables(variable_name)

              return_value = variable_com_object.Value

          except Exception as e:

              raise RuntimeError("CANoe is not open,unable to")

          return return_value

   

      def set_system_variable_value(self, ns_name, sysvar_name, var):

          """

          设置系统环境变量的值,这里对该值进行了判断,如果类型不对设置会直接报错

          :param ns_name:

          :param sysvar_name:

          :param var:

          :return:

          """

          namespace = '::'.join(sys_var_name.split('::')[:-1])

          variable_name = sys_var_name.split('::')[-1]

          try:

              namespace_com_object = self.application.System.Namespaces(namespace)

              variable_com_object = namespace_com_object.Variables(variable_name)

              if isinstance(variable_com_object.Value, int):

                  variable_com_object.Value = int(value)

              elif isinstance(variable_com_object.Value, float):

                  variable_com_object.Value = float(value)

              else:

                  variable_com_object.Value = value

              self.log.info(f'system variable({sys_var_name}) value set to -> {value}.')

          except Exception as e:

              self.log.info(f'failed to set system variable({sys_var_name}) value. {e}')

   

      def load_test_setup(self, testsetup):

          """

          这里方法是通过一个tse文件来加载一个testmode,如果要在canoe中找到的话,可以打开test界面找到

          我们的测试项目可以直接打开路径找到tse文件

          :param testsetup:

          :return:

          """

          self.TestSetup = self.App.Configuration.TestSetup

          path = os.path.join(self.ConfigPath, testsetup)

          print("传入的tse路径:", path)

          # 如果目标 tse 已存在,直接读取,否则添加它,如果已经存在,直接add的话会报错

          tse_count = self.TestSetup.TestEnvironments.Count

          print("add前tse数量:", tse_count)

          _existTse = False

          for _index_tse in range(1, tse_count + 1):

              """

              这里是为了保证我们传入tse如果已经被canoe加载,那么在Add path的时候会报错,所以一定要这样判断

              """

              if self.TestSetup.TestEnvironments.Item(_index_tse).FullName == path:

                  testenv = self.TestSetup.TestEnvironments.Item(_index_tse)

                  _existTse = True

                  break

          if _existTse == False:

              testenv = self.TestSetup.TestEnvironments.Add(path)

   

          print("add后tse数量:", self.TestSetup.TestEnvironments.Count)

   

          testenv = CastTo(testenv, "ITestEnvironment2")

          # TestModules property to access the test modules

          self.TestModules = []

          self.TraverseTestItem(testenv, lambda tm: self.TestModules.append(CanoeTestModule(tm)))

   

      def TraverseTestItem(self, parent, testf):

          for test in parent.TestModules:

              testf(test)

          for folder in parent.Folders:

              found = self.TraverseTestItem(folder, testf)

   

      def run_all_test_models(self):

          """ 启动所有测试模块,直到所有测试停止再结束这个函数"""

          # start all test modules

          for tm in self.TestModules:

              tm.Start()

          # wait for test modules to stop

          while not all([not tm.Enabled or tm.IsDone() for tm in self.TestModules]):

              DoEvents()

   

      def run_one_test_model(self, tese_model_name):

          """ 启动某个测试模块,直到所有测试停止再结束这个函数"""

          # 启动指定名称的测试模块

          for tm in self.TestModules:

              if tm.Name == tese_model_name:

                  tm.Start()

          # 等待指定名称的测试模块完成或禁用

          for tm in self.TestModules:

              if tm.Name == tese_model_name:

                  while not all([not tm.Enabled or tm.IsDone()]):

                      DoEvents()

              else:

                  continue

   

   

  class CanoeTestModule:

      """Wrapper class for CANoe TestModule object"""

   

      def __init__(self, tm):

          self.tm = tm

          self.Events = DispatchWithEvents(tm, CanoeTestEvents)

          self.Name = tm.Name

          self.IsDone = lambda: self.Events.stopped

          self.Enabled = tm.Enabled

   

      def Start(self):

          if self.tm.Enabled:

              self.tm.Start()

              self.Events.WaitForStart()

   

   

  class CanoeTestEvents:

      """Utility class to handle the test events"""

   

      def __init__(self):

          self.started = False

          self.stopped = False

          self.WaitForStart = lambda: DoEventsUntil(lambda: self.started)

          self.WaitForStop = lambda: DoEventsUntil(lambda: self.stopped)

   

      def OnStart(self):

          self.started = True

          self.stopped = False

          print("<", self.Name, " started >")

   

      def OnStop(self, reason):

          self.started = False

          self.stopped = True

          print("<", self.Name, " stopped >")

   

   

  class CanoeMeasurementEvents(object):

      """Handler for CANoe measurement events"""

   

      def OnStart(self):

          CanoeSync.Started = True

          CanoeSync.Stopped = False

          print("< measurement started >")

   

      def OnStop(self):

          CanoeSync.Started = False

          CanoeSync.Stopped = True

          print("< measurement stopped >")

  在这段代码中实现了canoe的一些基本功能,我们我们可以直接使用,但是注意如果是在子线程中调用canoe需要自己实现com口的初始化

  import pythoncom

  pythoncom.CoInitialize()  # 初始化COM口

  canoe_obj = None

  try:

      canoe_obj = CANoe()

      canoe_obj.open_cfg('path')

      

      # 在finally块中添加条件检查,确保对象存在再调用方法

      if canoe_obj:

          canoe_obj.stop_measurement()

          canoe_obj.close_cfg()

  finally:

      pythoncom.CoUninitialize()  # 清理COM口

  这样我们可以在子线程中使用canoe的调用,是否是会报错的。

  关于canoe的调用还有一个第三方的包:py_canoe

  在实际中这个包会出现一个问题,就是重复多次的关闭canoe会报错,或者重复多次加载不同的cfg文件也会报错

  角色认证

  如果你涉及到canoe的角色认证,其实可以通过设置启动系统环境变量来实现,因为他的角色认证都是跟系统环境变量相关,如local认证,你点击灯会变绿,都是都是对应的系统环境变量的值在发生改变,设置会相同的就可以实现认证。