python编写测试用例

开发一个系统,在开发代码时,测试是必不可少的,这里简单总结一下该怎么编写测试用例

例子:开发一个某系统,前端想要查询某个模块的数据,或着想对某个模块的数据进行增删改查,需要将参数信息传给后端,后段会有一个验证模块,验证传输过来的参数信息是否符合规范,不符合则抛异常,符合则按照前端的需求,进入相应的模块函数完成查询或者增删改查,之后将结果返回给前端。

大致流程:设置表格规范-->编写测试用例-->通过测试用例的报错,编写逻辑代码

1、设置规范

该部分的意义是,对数据库中的表设置规范,该部分就是上述所说的验证,对前端传来的参数进行验证,不符合规范则抛异常

schemas.py

from pydantic import BaseModel

class MemuAdd(BaseModel):   #对MemuAdd表里的字段进行设置

directory_id: PositiveInt = Field(title="目录ID")        #设置directory_id字段为正整数

memu_id: PositiveInt = Field(title="菜单ID")    #设置memu_id字段为正整数

display_index: int = Field(title="显示序号")    #设置display_index字段为整数

这样一个规范就设置好了,前端传来的参数,必须先经过这里进行验证。

2、测试1

我们是写后端的,没有前端传来参数,自己该怎么测试代码是否正确,python有专门的模块用来进行单元测试,就是unittest模块

TestCase类:一个TestCase的实例就是一个测试用例。什么是测试用例呢?就是一个完整的测试流程,包括测试前准备环境的搭建(setUp),执行测试代码 (run),以及测试后环境的还原(tearDown)。元测试(unit test)的本质也就在这里,一个测试用例是一个完整的测试单元,通过运行这个测试单元,可以对某一个问题进行验证。

test_schema_menu.py

import unittest,schemas

class TestCase(unittest.TestCase):
    def setUp(self):
        self.param={
            "directory_id":1,
            "display_index":1,
            "memu_id":1
        }

    def test_add(self):   
        schemas.MemuAdd(**self.param)  #将上述参数传递给schemas.MemuAdd,来验证传递的参数的规格符不符合要求
    
    def test_add_directory_id(self):
        self.param["directory_id"]=["1","2"]
        with self.assertRaises(ValueError): #故意将一个参数修改不规范,然后传递给schemas.MemuAdd,然后看是否能将异常捕获到
            schemas.MemuAdd(**self.param)

    def test_add_display_index(self):
        self.param["display_index"]=["1","2"]
        with self.assertRaises(ValueError):
            schemas.MemuAdd(**self.param)
    
    def test_add_memu_id(self):
        self.param["memu_id"]=["1","2"]
        with self.assertRaises(ValueError):
            schemas.MemuAdd(**self.param)

上述代码咱们看test_add_directory_id(self)函数,里面故意将一个参数修改成不规范的,然后通过with self.assertRaises(ValueError)捕获异常,假如咱们不添加捕获异常代码,然后进行测试,会直接报错:

ERROR: test_add_directory_id (tests.test_schema_menu_test.TestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/app/tests/test_schema_menu_test.py", line 17, in test_add_directory_id
    schemas.MemuAdd(**self.param)
  File "pydantic/main.py", line 406, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for MemuAdd
directory_id
  参数类型错误 (type=value_error)

有些人就想,这不挺好吗,报错信息一目了然。虽然报错信息一目了然,但是要记住,报错是要给前端用户去看,告诉他输入参数有误,而不是给后端开发人员看的,咱们需要将报错信息捕获到然后传给前端。所以需要加入with self.assertRaises(ValueError)捕获异常。

这样一个简单的测试用例就写完了,上述只是对一些输入参数的类型进行一个判断,下面写一个对数据库进行操作的测试用例

3、对数据库操作的测试用例

首先我们先写测试用例,然后根据测试用例的报错,来完善逻辑代码,测试用例的代码,在下方,均以作出解释。

decorator = tests.decorator_create_object(class_name=BaseMenu)  #封装一个类,这个不用太在意,对测试影响不大,所以就不说这个了,decorator_create_object是我本地的一个函数,不是模块。

class TestCase(TestCase):
    def setUp(self):
        tests.clear_table(models.MenuModel) #初始化表格,将表格数据清空

        records = [
            models.MenuModel(id=8, display_index=1, menu_id=1,directory_id=1,create_time=datetime.datetime.now(),
                        update_time=datetime.datetime.now() + datetime.timedelta(days=1)),
            models.MenuModel(id=9, display_index=2, menu_id=2,directory_id=2,create_time=datetime.datetime.now(),
                        update_time=datetime.datetime.now() + datetime.timedelta(days=1)),
            models.MenuModel(id=10, display_index=3, menu_id=3,directory_id=3,create_time=datetime.datetime.now(),
                        update_time=datetime.datetime.now() + datetime.timedelta(days=1)),
        ]
        tests.insert(records)  #将上述的参数信息写入表格
        self.param = {       #自定义一个参数,方便一会测试增加数据
                "directory_id":4,
                "display_index":4,
                "memu_id":4
        }
    
    def tearDown(self) -> None:  #这个上面介绍TestCase说过,这里就不说了
        ...

上述是一部分代码,主要是建立一个测试环境,下面我们来测试增加数据这个用例。

    #增加
    @decorator
    def test_add(self, *, object):
        param=schemas.MemuAdd(**self.param)  #这个就是上述第一部分说的,判断传来的参数类型是否符合要求
        result=object.add(param)   #这个就是调用逻辑代码里的add函数,object跟上面的decorator = tests.decorator_create_object(class_name=BaseMenu)有关系,所以这里不做过多解释,只要知道这里是调用逻辑代码里的add函数就行
        self.assertEqual(0,result["code"],"添加失败")  #assertEqual 用来判断 参数1和参数2是否相等,不相等则输出参数3,相等不做操作,这里主要看是否添加成功,如果添加成功,逻辑代码就会返回code=0,如果不成功,就会返回其他值

        verify_db=tests.fetch_by_id(models.MenuModel,result["data"]["id"])  #这行代码主要是去数据库查数,看数据是否真正插入成功,这里fetch_by_id也是我本地代码,不是一个模块,这个代码我将放到下方
        self.assertEqual(4,verify_db.directory_id,"目录ID添加失败") #这里就是判断查出来的数据是否和刚刚自己想要插入的数据是否相同
        self.assertEqual(4,verify_db.display_index,"显示序号添加失败")
        self.assertEqual(4,verify_db.menu_id,"菜单ID添加失败")

#测试输入一个不允许重复的字段的数值,看是否会报出“不允许重复”
    @decorator
    def test_add_memu_id(self,*,object):
        self.param["memu_id"]=1
        param=schemas.MemuAdd(**self.param)
        result=object.add(param)
        self.assertEqual(201002,result["code"],"菜单ID已存在,不能重复添加")

--------------------------------------------------------------------------
def fetch_by_id(model, id):
    with models.session_maker() as session:
        return session.query(model).filter_by(id=id).first()

上述的代码执行一遍后,输出如下,因为逻辑代码没写,所以def test_add()这个函数最后code默认返回0,所以没报错。主要是看def test_add_memu_id(self,*,object),看下面报错显示出来了,报“AssertionError: 201002 != 0 : 菜单ID已存在,不能重复添加“,我们需要在逻辑代码里把这个异常捕获,然后传递给前端。下面就按照测试用例的报错去写逻辑代码

FAIL: test_add_memu_id (tests.test_class_menu_test.TestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/app/tests/__init__.py", line 59, in wrapper
    result = function(*args, **kwargs)
  File "/app/tests/test_class_menu_test.py", line 73, in test_add_memu_id
    self.assertEqual(201002,result["code"],"菜单ID已存在,不能重复添加")
AssertionError: 201002 != 0 : 菜单ID已存在,不能重复添加

逻辑代码: 

from .ssobaseclass import SSOBaseClass
model = MenuModel  #表名称


class BaseMenu(SSOBaseClass):
    @catch_exception
    def add(self, param:schemas.MemuAdd):
        directory_id=param.directory_id
        memu_id=param.memu_id
        display_index=param.display_index
        
        session=self.context.session  #这个是创建会话,用于数据库操作,具体可以看我文章里有一个专门介绍python对数据库操作
        row_memu_id=session.query(model).filter(model.menu_id==memu_id).first()  #这个就是在数据库中进行搜索
        if row_memu_id:  #如果搜索出来有值,说明数据库里有这个菜单ID,所以本次不能去添加,添加的话就重复了,所以我们通过下面的代码进行抛出异常。
            raise SSOException(201002,"菜单ID不能重复")
        

 ##下面这一堆就是写入数据库操作,具体可以看我文章里有一个专门介绍python对数据库操作    Menu=model(directory_id=directory_id,menu_id=memu_id,display_index=display_index)
        Menu.create_time = datetime.datetime.now()
        Menu.update_time = datetime.datetime.now()
        session.add(Menu)
        session.commit()

         # 记录操作日志
        self.context.add_oplog(event_type="添加菜单", content=f"添加了菜单:{Menu.menu_id}", target_id=Menu.id)
        return{
            "id":Menu.id
        }

逻辑代码写完以后,我们在执行一遍测试用例,就会发现没有报错,说明报错被我们捕获了,这就说明我们成功了,捕获到就可以返回给前端了

root@3f6fe561aa49:/app# ./unittest.sh 
...............
----------------------------------------------------------------------
Ran 15 tests in 0.294s

OK

这样一个大致的测试用例就完结了,也不仅仅只有测试用例,也写到怎么写逻辑代码,可能内容比较多,写的不是很明确,之后还得需要读者慢慢消化,慢慢理解,其实理解了流程,其他都好说,流程不知道,看代码就是一塌糊涂。

通过Python编写测试用例并自动化测试CANoe,可以使用CANoe提供的CAPL语言编写测试用例。具体步骤如下: 1. 编写CAPL测试用例,包括测试用例名称、测试用例步骤、期望结果等信息。 2. 使用Python的xml.etree.ElementTree模块创建XML格式的测试用例文件,将CAPL测试用例转换为XML格式。 3. 在Python中读取XML格式的测试用例文件,并解析其中的测试用例信息。 4. 使用Python的win32com模块连接CANoe,并获取CANoe的Application对象。 5. 通过Application对象获取Measurement对象,并启动测量。 6. 通过Measurement对象获取MeasurementSetup对象,并加载测试用例。 7. 通过MeasurementSetup对象获取TestExecution对象,并开始测试。 8. 测试完成后,通过TestExecution对象获取测试结果,并保存结果。 代码示例: ```python import win32com.client as win32 import xml.etree.ElementTree as ET # 编写CAPL测试用例 capl_test_case = """ testcase TC_001 { teststep "Step 1" { // 执行测试步骤 } teststep "Step 2" { // 执行测试步骤 } expect "Expected Result" { // 验证测试结果 } } """ # 创建XML格式的测试用例文件 root = ET.Element("testcases") test_case = ET.SubElement(root, "testcase") test_case.set("name", "TC_001") test_step1 = ET.SubElement(test_case, "teststep") test_step1.set("name", "Step 1") test_step2 = ET.SubElement(test_case, "teststep") test_step2.set("name", "Step 2") expect_result = ET.SubElement(test_case, "expect") expect_result.set("name", "Expected Result") tree = ET.ElementTree(root) tree.write("test_case.xml") # 读取XML格式的测试用例文件 tree = ET.parse("test_case.xml") root = tree.getroot() test_case_name = root[0].get("name") test_step1_name = root[0][0].get("name") test_step2_name = root[0][1].get("name") expect_result_name = root[0][2].get("name") # 连接CANoe canoe = win32.Dispatch("CANoe.Application") # 获取Measurement对象 measurement = canoe.Measurement # 启动测量 measurement.Start() # 获取MeasurementSetup对象 measurement_setup = measurement.MeasurementSetup # 加载测试用例 measurement_setup.Load("test_case.xml") # 获取TestExecution对象 test_execution = measurement_setup.TestExecution # 开始测试 test_execution.Start() # 获取测试结果 result = test_execution.Result # 保存测试结果 result.Save("test_result.xml") # 停止测量 measurement.Stop() ``` 需要注意的是,CAPL测试用例需要根据实际情况进行编写,并将测试用例转换为XML格式。在XML格式的测试用例文件中,需要包含测试用例名称、测试用例步骤、期望结果等信息。在使用Python连接CANoe并进行自动化测试时,需要先加载测试用例文件,然后开始测试并获取测试结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值