pytest+allure+excel实现python调CANoe进行诊断自动化测试(二)

一、前言

本文主要介绍整体框架构成及python调CANoe COM接口封装的方法

二、测试框架的好处

当我们开发软件时,需要确保软件的各个部分能正常工作。为了做到这一点,我们需要测试软件,即检查软件是否按照我们预期的方式运行。传统的测试通常是手动的,即人工点击按钮、输入数据来模拟用户行为,来检查软件功能是否正常。但是这种方式效率低下且容易出错。
为了提高测试效率和质量,我们可以构建一个自动化测试框架。这个框架就像一个机器人,能自动执行测试用例,验证软件的功能是否正常。构建自动化测试框架的好处是可以节省时间和人力资源,并确保每次更新后软件依然正常运行。同时,自动化测试框架可以帮助我们更方便地合作,共享测试用例和结果,确保软件质量。因此,构建自动化测试框架可以帮助我们更快速、更准确地测试软件,确保软件质量。

主要好处分为以下几点:

1. 提高测试效率:自动化测试框架可以自动执行测试用例,省去了手动测试的时间和劳动成本。测试团队可以更快速地执行测试,并及时发现问题。
2. 提高测试覆盖率:自动化测试框架可以帮助测试团队更全面地覆盖功能、边界条件和各种场景,确保软件质量。
3. 降低测试成本:虽然构建自动化测试框架需要一定的投入,但长期来看,自动化测试可以减少重复劳动和人力资源成本。同时,自动化测试框架可以更快速地应对软件变更,减少因人为错误导致的质量问题。
4. 提高持续集成与交付软件的速度:自动化测试框架可以与持续集成工具(如 Jenkins)和持续交付流程结合,确保每次代码提交都能进行自动化测试,从而提高软件交付速度和质量。
5. 方便协作与回归测试:构建自动化测试框架可以使测试团队更容易共享测试用例和测试结果,方便团队合作。同时,自动化测试框架可以帮助团队更方便地进行回归测试,确保每次更新后软件依然符合预期。

三、框架构成

从上往下依次介绍:

allure-report

主要存放生成完的allure测试报告,之后执行结束后打开index.html即可查看完整的测试报告

comm

存放公用方法,因为是自动化测试框架嘛,后面后其他自动化测试要实现时需要用到的公用方法都在此处存放使用

canoe_application.py主要是python调CANoe的方法封装

execute_excel.py主要是读写excel的方法

security_key.py主要是进行安全解锁的方法

log

用于存放日志,目前只存放了CANoe生成的trace日志

report

存放allure生成的json文件。

Allure生成的.json文件是一种用于存储测试结果数据的格式化文件。通常,当运行测试并生成Allure测试报告时,Allure会生成.json文件来存储测试执行的详细信息,包括测试用例的执行结果、测试用例的状态、测试步骤的日志、附加信息等

里面的environment.properties是allure报告的配置文件

testcase

存放的是测试脚本。

testdata

存放测试数据。

根目录下的文件

config.ini:配置路径、设备等

environment.properties:测试报告环境配置,方便复制到allure生成的json文件中

main.py:执行文件

四、python调CANoe COM封装

canoe_application.py

import os
import time
from win32com.client import *
from pathlib import Path

class CANoe:
    def __init__(self):
        # self.application = None
        self.application = DispatchEx("CANoe.Application")
        self.ver = self.application.Version
        print('Loaded CANoe version', self.ver.major, '.', self.ver.minor, '.', self.ver.Build, '...')
        self.logging_collection = None
        self.logger = None
        self.log_target_dir = None
        self.Measurement = self.application.Measurement.Running

    def open_cfg(self, cfgname):
        """
        打开工程
        :param cfgname:
        :return:
        """
        if(self.application != None):
            if os.path.isfile(cfgname) and (os.path.splitext(cfgname)[1] == '.cfg'):
                self.application.Open(cfgname)
                print("opening..."+cfgname)
            else:
                raise NameError("Can't find CANoe cfg file")
        else:
            raise RuntimeError("CANoe Application is missing, unable to open simulation")


    def close_cfg(self):
        """
        关闭工程
        :return:
        """
        if(self.application != None):
            self.application.Quit()
            self.application = None

    def start_Measurement(self):
        """
        运行
        :return:
        """
        retry = 0
        retry_counter = 5  # 尝试5次
        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 measurement failed, Please Check Connection!")

    def stop_Measurement(self):
        """
        停止
        :return:
        """
        if self.application.Measurement.Running:
            self.application.Measurement.Stop()
        else:
            pass

    def send_Diag_Request(self, qualifier, stream_flag=False):
        """
        发送诊断请求
        :param qualifier: 限定符
        :param stream_flag: 是否是给定的限定符
        :return:
        """
        data = qualifier
        my_bytearray = bytearray.fromhex(data)
        qualifier_list = list(my_bytearray)
        self._diag_Request(qualifier_list, stream_flag)

        # self.DiagDev = self.application.Networks("CAN").Devices("EPS").Diagnostic
        # self.DiagReq = self.DiagDev.CreateRequest('0x10 0x01')
        # self.DiagReq.Send()
        # self.Diag.DiagStartTesterPresent()

    def init_service(self, network, device):
        """
        建立诊断服务
        :param network: 网段
        :param device: ECU qualifier
        :return:
        """
        time.sleep(10)
        self.__gDiag = self.application.Networks(network).Devices(device).Diagnostic
        # self.__gDiag.DiagStartTesterPresent()


    def start_TesterPresent(self):
        """
        开启诊断仪在线
        :return:
        """

        self.__gDiag.DiagStartTesterPresent()

    def stop_TesterPresent(self):
        """
        停止诊断仪在线
        :return:
        """
        self.__gDiag.DiagStopTesterPresent()

    def _diag_Request(self, qualifier, stream_flag=False):
        """
        执行服务
        :param qualifier:
        :param stream_flag: True以字节流形式发送,False根据具体限定符发送
        :return:
        """

        global diag_request
        if stream_flag:
            pass
        else:
            for a in qualifier:
                print('%x' % a, end=' ')
        if not stream_flag:
            diag_request = self.__gDiag.CreateRequest(qualifier)
        else:
            diag_request = self.__gDiag.CreateRequestFromStream(bytearray(qualifier))
            # else:
            #     diag_request = self.__gDiag.SetComplexParameter(bytearray(qualifier), iteration, subParameter)

        diag_request.Send()

    def check_Diag_Response(self):
        return self._diag_Response()

    def check_positive(self):
        global diag_request
        Res = ''
        while diag_request.Pending:
            time.sleep(1)
        if diag_request.Responses.Count == 0:
            Res = "NO RESPONSE"
        else:
            for k in range(1, diag_request.Responses.Count + 1):
                diag_resp = diag_request.Responses(k)
                stream = diag_resp.Stream
            if diag_resp.Positive:
                return True
            else:
                return False

    def _diag_Response(self):
        """
        诊断响应
        :return:
        """
        global diag_request
        Res = ''
        positive = True
        while diag_request.Pending:
            time.sleep(1)
        if diag_request.Responses.Count == 0:
            Res = "NO RESPONSE"
        else:
            for k in range(1, diag_request.Responses.Count + 1):
                diag_resp = diag_request.Responses(k)
                stream = diag_resp.Stream
            if diag_resp.Positive:
                positive = True
            else:
                positive = False

            for i in stream:
                Res = Res + '{:02X} '.format(i)
        return Res, positive


    def init_logging_collection(self):
        """

        :return:
        """
        self.logging_collection = self.application.Configuration.OnlineSetup.LoggingCollection

    def select_logger(self, logger_number:int = None):
        """

        :param logger_number:
        :return:
        """
        self.logger = self.logging_collection.Item(logger_number)

    def set_log_target_dir(self, abs_path_to_dir = None):
        """

        :param abs_path_to_dir: log存放位置
        :return:
        """
        path = Path(abs_path_to_dir)
        if path.exists():
            self.log_target_dir = path
        else:
            raise Exception("CANoe Wrapper: Log target directory does not exist")

    def set_logfile_name(self, file_name:str = None):
        """

        设置日志名字
        :param file_name:
        :return:
        """
        file = Path(file_name)
        if file.suffix == '.blf':
            full_path = Path.joinpath(self.log_target_dir, file)
            self.logger.fullName = str(full_path)
        else:
            raise Exception("CANoe Wrapper: Log target file has incorrect extension")

    def start_logging(self):
        """
        开始记录日志
        :return:
        """
        if self.logger is not None:
            self.logger.Trigger.Start()
        else:
            raise Exception("CANoe Wrapper: No active logger was set")

    def stop_logging(self):
        """
        停止记录日志
        :return:
        """
        if self.logger is not None:
            self.logger.Trigger.Stop()
        else:
            raise Exception("CANoe Wrapper: No active logger was set")

    def get_logger_status(self):
        """
        获取日志状态
        :return: 返回TRUE 表示log状态为running,返回FALSE 表示log状态为stopped
        """
        if self.logger is not None:
            return str(self.logger.Trigger.Active)

    def sleep(self, ms:int):
        time.sleep(ms/1000)



if __name__ == '__main__':
    app = CANoe()
    app.open_cfg(r"D:\work\Partial_SDA\workspace\canoeworkspace\ECUTestwork.cfg")
    time.sleep(1)

CANoe的COM接口在帮助文档中可以找到:

  • 19
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python是一种广泛使用的编程语言,因其易学易用、灵活性和可扩展性而备受欢迎。requests是Python的一个库,它提供了一种简单且易于使用的方式来发送HTTP请求。pytestPython的另一个库,它提供了一种用于编写和运行测试的框架。allure是一个测试报告生成工具,可以为测试结果提供美观和易读的报告。 在接口自动化测试中,可以使用Python的requests库来发送HTTP请求,并使用pytest框架来编写和运行测试。可以使用Excel来存储测试数据、预期结果和实际结果。使用allure工具可以生成美观的测试报告。 以下是使用Python requests、pytestallure进行接口自动化测试的一般步骤: 1. 安装Python、requests、pytestallure 2. 创建一个Excel文件,输入测试数据、预期结果和实际结果 3. 创建一个pytest测试文件,并使用requests库发送HTTP请求,比较预期结果和实际结果 4. 在pytest测试文件中添加allure装饰器,以便生成测试报告 5. 运行pytest测试文件并生成allure测试报告 例如,以下是一个使用Python requests、pytestallure进行接口自动化测试的示例代码: ```python import requests import pytest import allure import openpyxl @allure.title("测试接口") @pytest.mark.parametrize("test_input, expected", [(1, "success"), (2, "fail")]) def test_api(test_input, expected): # 从Excel文件中获取测试数据和预期结果 wb = openpyxl.load_workbook("testdata.xlsx") sheet = wb.active test_data = sheet.cell(row=test_input, column=1).value expected_result = sheet.cell(row=test_input, column=2).value # 发送HTTP请求 response = requests.get("http://example.com/api", params=test_data) actual_result = response.text # 比较预期结果和实际结果 assert actual_result == expected_result, f"预期结果:{expected_result},实际结果:{actual_result}" # 添加allure描述 allure.attach("请求参数", str(test_data)) allure.attach("预期结果", str(expected_result)) allure.attach("实际结果", str(actual_result)) ``` 在上面的代码中,使用了pytest的parametrize装饰器来传递测试数据和预期结果。使用openpyxl库从Excel文件中获取测试数据和预期结果。使用requests库发送HTTP请求并比较预期结果和实际结果。使用allure的装饰器来添加测试描述。最后,运行pytest测试文件并生成allure测试报告。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值