使用Python访问CANoe COM接口实践

服务器

  前言

  CANoe提供的COM接口使得外部脚本能够访问或控制CANoe软件,从而实现自动化测试任务,而易用且具有丰富生态的Python无疑是一个很好的选择。本文将介绍CANoe COM基本构成、常用COM对象以及Python脚本调用CANoe COM的方法,在此之前,先介绍一些基本概念。

  CANoe COM Server & Python pywin32

  COM全称Component Object Model,是微软为Windows平台软件提出的、实现软件之间互操作的标准。它不会规定软件的具体实现,而是声明一种对象模型,使得满足这种模型的对象之间能交互,这些对象通常被称为组件(Component)。组件会实现特定的功能,而这些功能以特定的方式提供——即接口(Interface),其他组件通过接口使用它们。另外,组件需要经过注册(Registry),才能被其他软件发现和使用。注册后的组件向其他软件提供服务,因此组件将作为服务端(COM Server),其他想要使用服务的作为客户端(COM Client)。

  在安装完成CANoe软件后,CANoe已经在Windows组件服务管理器中注册了CANoe COM Server,如果需要重新注册,可以在安装目录下(默认为C:\Program Files\Vector CANoe 14)的Exec64文件夹中找到RegisterComponents.exe,运行即手动注册。

  Python pywin32 package,它提供了许多Python扩展以调用Windows API,其中就包括COM组件,由于Python脚本将使用CANoe COM提供的服务,因此Python脚本将作为COM Client,在pywin32包中就对应win32com.client模块,所以后续的Python脚本都要导入win32com.client模块。

  了解以上的概念后,下面就看看本文的主要内容。

  COM Object Hierarchy

  在CANoe中,各个功能模块按照一定的层级组织在一起构成整个CANoe软件。与这些功能模块直接相关的COM组件同样也是按照相应的层级组织的,这就形成了COM Object Hierarchy:

  如上图所示,图的最左侧是Application对象,是访问其他对象的入口;通过它可以访问Configuration对象,而通过Configuration对象才能访问CommunicationSetup对象;要想设置CommunicationSetup,就需要按照Application->Configuration->CommunicationSetup从左向右的层级顺序,找到相应的属性或是方法,从而实现设置。

  Type Library

  了解COM Object Hierarchy能帮助快速找到所需功能,但是不能知道实现所需功能对象的继承关系,为此还需要了解CANoe Type Library。在CANoe软件安装目录下(默认为C:\Program Files\Vector CANoe 14)的Exec32\COMdev目录中包含了注册COM所用的类型库,如下图所示CANoe.h头文件:

  在CANoe.h头文件中包含所有CANoe COM对象的接口定义,比如ITestConfiguration接口:

  而如果想要设置TestConfigurationSettings对象,从COM Object Hierarchy得知需要从TestConfiguration对象访问:

  但是在Type Library中Configuration对象有多个ITestConfiguration接口,比如:

  可以看到,ITestConfiguration2继承自ITestConfiguration,在它的基础上又扩充了许多方法,比如获取TestConfigurationSettings对象的方法get_Settings就在其中。

  也就是说,要通过实现了ITestConfiguration2接口的TestConfiguration对象的get_Settings方法,才能获得TestConfigurationSettings对象。

  为此,通过win32com.client模块中的CastTo方法,能将TestConfiguration转换成基于ITestConfiguration2接口的对象。

  COM Object

  COM Object Hierarchy中有许多COM对象,短时间内掌握所有COM对象是不现实的,下面仅针对常用的、与自动化测试紧密相关的COM对象做介绍。

  Application

  使用Python控制CANoe,首先要获取关联整个CANoe进程的COM对象,也就是Application对象。通过Dispatch方法就可以获得关联到当前CANoe进程的COM对象,如果当前并没有CANoe进程,则会启动一个CANoe进程;而如果想要另外获得一个CANoe进程,则可以使用DispatchEx方法。

  下面是获取Application对象的代码示例:

  在以上示例中,CANoe各部分功能封装在CANoe类中,在CANoe类初始化时,把获得的Application对象保存在CANoe类的App成员中,这样在CANoe类的其他方法中,就可以通过使用App成员来访问Application对象。

  有了Application对象,才能访问CANoe工程的各个功能模块,比如打开CANoe工程:

  而在open_canoe_config方法中,使用Application对象的Open方法打开特定的CANoe工程,具体Application对象的接口定义(这里仅展示IApplication的部分方法,其他方法以及后续扩展的方法并未展示)如下:

  Measurement

  要想控制CANoe启动测量,就需要获取Measurement对象,对于上面获得的Application对象,使用self.App.Measurement获得。

  在Measurement对象的接口定义中,可以看到Start方法,使用Measurement.Start()就能启动CANoe测量。

  下面是启动CANoe测量的代码示例:

  System Variables

  系统变量作为CANoe中重要的部分,要想获取任意系统变量的值,就要获取对应系统变量的对象。

  从COM Object Hierarchy中可以看到,系统变量Variable对象是按照Application->System->Namespaces->Namespace->Variables->Variable顺序访问的。

  其中Namespaces和Variables分别表示Namespace和Variable对象的集合,因此可以使用Namespace名称(Variable名称)作为索引,从Namespaces(Variables)中获得相应的Namespace(Variable)对象。

  另外,在Variable对象的接口定义中,可以看到get_Value和put_Value方法,而Python将这两种方法转变成了Value属性,也就是说可以直接对Variable.Value取值或赋值。

  下面是获得系统变量值的代码示例:

  在以上示例中,添加了简单的异常处理可以暂且不看,仅考察if分支中的语句。首先,使用self.App.System.Namespaces获得Namespaces对象,将其保存在system_namespaces变量中;然后使用刚保存的变量,以ns_name作为索引获得Namespace对象并保存在sys_namespace变量中;再通过sysvar_name索引获得Variable对象sys_variable,最后返回sys_variable.Value属性值。

  Test Configuration & Test Unit

  与自动化测试 (这里仅介绍Test Configuration配置,即与vTESTstudio软件联合使用的自动化测试)直接相关的就是Test Configuration以及Test Unit,前者对应整个测试执行的设置,后者包含具体执行的测试用例。在COM Object Hierarchy中可以看到,它们的层级构成为Application->Configuration->TestConfigurations->TestConfiguration->TestUnits->TestUnit:

  其中,TestConfigurations与TestUnits跟前文类似,表示TestConfiguration和TestUnit的集合,同样可以通过索引访问。除了可以使用相应TestConfiguration(TestUnit)名称作为索引以外,还能使用数字索引,但是切记索引起始为1。对于仅有一个TestConfiguration的情况,仅需要TestConfigurations(1)来获得唯一的TestConfiguration对象。

  当CANoe工程中还没有TestConfiguration或者TestUnit时,就需要先添加。查看它们的接口定义:

  可以看到Add方法能添加相应的对象,对于TestConfigurations.Add()不需要其他参数,即可添加并获得新的TestConfiguration对象;而TestUnits.Add()需要提供所要添加的TestUnit的绝对路径,同样可以获得对应的TestUnit对象。另外值得注意的是,TestUnits的Add方法是在ITestUnits2接口上扩展的,所以要通过前文所述的CastTo方法将TestUnits (默认为基于ITestUnits接口)转换成基于ITestUnits2的对象。

  下面请看加载测试配置的代码示例:

  在以上示例中,首先通过TestConfigurations.Add()方法新添加一个TestConfiguration对象,并把它保存为类成员self.test_config;之后使用CastTo方法将新添加的TestConfiguration中的TestUnits对象转换成基于ITestUnits2接口的TestUnits对象(默认为ITestUnits接口);最后使用转换后的TestUnits对象的Add方法,添加test_unit_path路径下的测试单元(.vtuexe文件)。

  加载测试配置后,还需要启动测试执行,查看ITestConfiguration接口定义,可以发现Start方法:

  下面是执行测试的代码示例(这里使用了之前保存的类成员self.test_config):

  执行完测试后,需要获得测试结果,可以通过CANoe软件为Test Configuration创建的系统变量VerdictSummary查看:

  下面是获得测试结果的代码示例:

  这里get_test_result方法有一个带有默认值的参数test_config_name表示实际执行测试的TestConfiguration名称,它的默认值是Test_Configuration_1,如果没有修改过就不需要提供参数,否则需要提供;get_test_result返回保存在VerdictSummary中的测试结果,其数据类型是整型,需要在接口定义中查询具体数值对应的结果:

  Test demo

  联合使用上述COM对象就能够实现自动化测试,下面展示完整的代码示例:

  基于Canoe类,就可以通过实例化Canoe类,调用实例对象的方法来实现自动化测试,下面是简单的代码示例:

  首先,实例化Canoe类,将实例化后的对象保存在canoe变量中;之后定义了canoePrj变量表示CANoe工程的绝对路径,然后使用open_canoe_config方法打开此工程;接着定义testPrj变量表示测试单元可执行文件的绝对路径,使用load_test_config方法加载测试单元;然后使用start_canoe方法启动CANoe测量,等待2s后,使用run_test_config方法执行测试,等待10s后测试停止;最后打印通过get_test_result方法获得的测试结果。

  这里使用了Vector CANoe 14自带的PythonBasicEmpty.cfg demo工程作为测试工程,下面是关于此demo的介绍文档:

  这个demo中有更丰富的COM对象的应用、更完善的信息提示,比如对测试启动、停止等事件的控制,对CANoe运行状态的打印,在此不再赘述。

  最后,运行以上脚本后,可以获得自动化测试结果,对照前文的VerdictState,可以确定测试通过:

  总结

  本文介绍了使用Python访问CANoe COM以实现自动化测试的基本方法,通过几个常用的COM对象及方法,构建了简单的自动化测试示例工程。对于更复杂的工程,同样可以根据基本方法,灵活运用COM以满足测试需求。进一步,可以将CANoe COM封装成Python库,利用可复用性高效地完成针对不同需求的自动化测试。

  CANoe是德国Vector公司出的一款总线开发环境,是网络和ECU开发、测试和分析的专业工具,从需求分析到系统实现的整个系统开发过程;其丰富的功能和配置选项被OEM和供应商的网络设计工程师、开发工程师和测试工程师所广泛使用。

  北汇信息作为Vector中国的合作伙伴,不仅提供相应的工具和技术服务及培训,还针对不同的应用提供相应的解决方案,助力中国客户的研发效率提升。

  注:本文部分图片来自Vector。

标签: 服务器