公共用例库计划--个人版(六)典型Bug页面设计与开发

1、任务概述

本次计划的核心任务是开发一个,个人版的公共用例库,旨在将各系统和各类测试场景下的通用、基础以及关键功能的测试用例进行系统性地归纳整理,并以提高用例的复用率为目标,力求最大限度地减少重复劳动,提升测试效率。

计划内容:完成公共用例库的开发实施工作,包括需求分析、系统设计、开发、测试、打包、运行维护等工作。

1.1、 已完成:

需求分析、数据库表的设计:公共用例库计划--个人版(一)

主体界面与逻辑设计:公共用例库计划--个人版(二)

导出Excel功能:公共用例库计划--个人版(三)

模块选择功能改造与性能优化公共用例库计划--个人版(四)

QtCharts制作首页饼图与柱状图公共用例库计划--个人版(五)

1.2、 本次待完成:

典型Bug:新增遇见的较典型的bug,进行复盘与经验总结。

1. bug、图片的库表设计

2. 典型Bug页面,界面设计

3. 逻辑代码开发

2、bug、图片的库表设计

计划创建两张表,一张表存放bug信息,一张表保存bug的图片。

建表语句:

python 复制代码
			# 创建bug表
            self.cursor.execute("""  
                            CREATE TABLE IF NOT EXISTS bug (  
                                bugid INTEGER PRIMARY KEY AUTOINCREMENT,  --编号
                                title TEXT NOT NULL,  --标题
                                types INTEGER ,  --类型--对应码值表code40-49
                                difficulty INTEGER ,  --难度--对应码值表code30-36
                                moduleid INTEGER ,  --所属模块
                                describe TEXT , --描述
                                think TEXT , --思考
                                severity INTEGER  --严重程度--对应码值表code50-53
                            )""")
            # 创建图片表
            self.cursor.execute("""  
                            CREATE TABLE IF NOT EXISTS image (  
                                imageid INTEGER PRIMARY KEY AUTOINCREMENT,  --编号
                                name TEXT NOT NULL,  --名称
                                image_bytes BLOB ,  --图片
                                bugid INTEGER  --所属bug
                            )""")

3、典型Bug页面

主要功能设计介绍:

左侧使用listWidget显示bug列表,有翻页功能。

主体上面,把用例页面的查询条件copy过来改改,选择条件对左边列表的bug进行查询。

主体中部,点击左侧列表中bug名称,显示对应bug的详细信息。有图片上传按钮,显示图片、翻页等功能按钮。

最后建了一个窗口,放一个graphicsView控件,显示大图。(上面页面图片是label显示的,担心显示太小了)

4、bug新增代码开发

4.1 保存bug

在设计页面时,对保存按钮增加信号槽,点击保存触发save_bug。

对标题、描述进行 必填验证。如果有获取到bugid,就走编辑流程,没有就新增bug。

python 复制代码
    def save_bug(self):
        """bug页面,保存"""
        if not self.lineEdit_4.text() or self.textEdit.toPlainText() == '[步骤]\n\n[结果]\n\n[期望]\n':
            self.ts.xinxi("标题或描述不能为空!")
            return

        self.save_bug_b.setEnabled(False)  # 保存按钮置灰
        parts=self.mk_2.currentText().split("---ID:")  # 模块编号
        if len(parts) == 2:
            self.mk_2.mkid=parts[1]
        else:
            self.mk_2.mkid=''
        if self.bugid != 0:  # 编辑
            vlue=(f'{self.lineEdit_4.text()}',
                  tc_sql.codes_dict['mk_types'][f'{self.lileixing_bug_2.currentText()}'],
                  tc_sql.codes_dict['difficulty'][f'{self.nandu_2.currentText()}'],
                  f'{self.mk_2.mkid}', f'{self.textEdit.toPlainText()}',
                  f'{self.textEdit_2.toPlainText()}',
                  tc_sql.codes_dict['severity'][f'{self.nandu_3.currentText()}'], f'{self.bugid}')
            self.savesql_bug(
                "update bug set title=? ,types=? ,difficulty=?, moduleid=? ,describe = ?,think = ?,severity=? where bugid=?",
                vlue)
        else:  # 新增
            vlue=(f'{self.lineEdit_4.text()}',
                  tc_sql.codes_dict['mk_types'][f'{self.lileixing_bug_2.currentText()}'],
                  tc_sql.codes_dict['difficulty'][f'{self.nandu_2.currentText()}'],
                  f'{self.mk_2.mkid}', f'{self.textEdit.toPlainText()}',
                  f'{self.textEdit_2.toPlainText()}',
                  tc_sql.codes_dict['severity'][f'{self.nandu_3.currentText()}'])
            self.savesql_bug("INSERT INTO bug VALUES (NULL,?,?,?,?,?,?,?)", vlue)

    def savesql_bug(self, sql, vlue):
        """bug保存sql"""
        self.case_db.connect()
        if self.case_db.operate_one(sql, vlue):
            self.case_db.over()
            self.chaxun_bug()  # 查询列表
            self.ts.xinxi("保存成功")
            logging.info('bug页面,保存')
        else:
            self.ts.xinxi("保存失败,请检查")
        self.save_bug_b.setEnabled(True)  # 保存按钮恢复

4.2 bug查询

在设计页面时,对每一个查询条件设计信号槽,触发查询按钮,查询按钮触发chaxun_bug。

先获取查询条件的信息,然后通过拼接条件sql,查询出对应的bug,写入bug列表显示。

python 复制代码
    def chaxun_bug(self, ye=1):
        """bug页面,查询"""
        parts=self.mk_1.currentText().split("---ID:")
        if len(parts) == 2:
            self.mk_1.mkid=parts[1]
        else:
            self.mk_1.mkid=''

        mk_types=tc_sql.codes_dict['mk_types'][
            f'{self.lileixing_bug.currentText()}'] if self.lileixing_bug.currentText() else ''
        difficulty=tc_sql.codes_dict['difficulty'][
            self.nandu.currentText()] if self.nandu.currentText() else ''

        dic={"bug.types": mk_types,
             "bug.difficulty": difficulty,
             "bug.moduleid": self.mk_1.mkid}
        dic_like={"bug.title": self.biaoti_bug.text()}
        sql1="select bugid || ':' || title from bug where"  # 拼接sql查询条件
        sql2="select count(*) from bug where"
        for k, v in dic.items():
            if v:
                sql1+=' ' + k + "= " + str(v) + " and"
                sql2+=' ' + k + "= " + str(v) + " and"
        for k, v in dic_like.items():
            if v:
                sql1+=' ' + k + " like '%" + v + "%' and"
                sql2+=' ' + k + " like '%" + v + "%' and"

        offset=20 * (ye - 1)  # 分页查询
        sql1=sql1.rstrip('where').rstrip('and') + " order by bug.bugid DESC " + f"LIMIT 20 OFFSET {offset}"
        sql2=sql2.rstrip('where').rstrip('and')

        self.case_db.connect()
        items=self.case_db.query_many(sql1)  # bug查询
        count=self.case_db.query_one(sql2)
        self.bugye_count=math.ceil(count[0] / 20)  # 页数计算
        self.case_db.over()
        self.listWidget.clear()  # 清空列表
        self.clear_bug()  # 清空页面
        if items:
            for i in range(len(items)):  # 数据写入列表
                item=QListWidgetItem(items[i][0])
                item.setToolTip(items[i][0])  # 写入提示
                self.listWidget.addItem(item)

            self.label_24.setText(f"总数: {count[0]}条 共: {self.bugye_count}页    ")
            self.lineEdit_3.setText(f"{ye}")
        else:
            self.listWidget.addItem("未查询到数据")  # 查询无数据,加空行
            self.label_24.setText(f"总数: 0条 共: 0页    ")
            self.lineEdit_3.setText("0")
        logging.info('bug页面,查询')

4.3 bug详情

查询出bug列表后,点击其中的bug,页面显示详情。对列表增加槽函数,点击触发show_bug。

获取点击的bugID,根据bugid查询出信息,回显到页面。

python 复制代码
    def show_bug(self):
        """点击bug,显示bug详情"""
        a=self.listWidget.selectedItems()
        if a:
            parts=a[0].text().split(":")
            if len(parts) == 2:
                self.bugid=parts[0]
            else:
                self.bugid=0
                return
            sql26='''select bug.title,codes1.value as types,codes2.value as difficulty,
                    module.modulename || '---ID:' || module.moduleid,
                    bug.describe,bug.think,codes3.value as severity
                    from bug 
                INNER JOIN
                    codes AS codes1 ON bug.types = codes1.id AND codes1.id BETWEEN 40 AND 49 -- 关联类型码值表
                INNER JOIN
                    codes AS codes2 ON bug.difficulty = codes2.id AND codes2.id BETWEEN 30 AND 36 -- 关联难度码值表
                INNER JOIN
                    codes AS codes3 ON bug.severity = codes3.id AND codes3.id BETWEEN 50 AND 53
                LEFT JOIN
                    module  ON bug.moduleid = module.moduleid 
                where bug.bugid = ? '''
            self.case_db.connect()
            items=self.case_db.query_one(sql26, (self.bugid,))  # bug查询
            self.case_db.over()
            # bug详情回显
            self.lineEdit_4.setText(items[0])
            index=self.lileixing_bug_2.findText(items[1], Qt.MatchFlag.MatchFixedString)
            self.lileixing_bug_2.setCurrentIndex(index)  # 设置下拉框内容
            index2=self.nandu_2.findText(items[2], Qt.MatchFlag.MatchFixedString)
            self.nandu_2.setCurrentIndex(index2)
            self.mk_2.clear()  # 清空模块下拉
            self.mk_2.addItem(items[3])
            self.mk_2.setCurrentIndex(0)  # 设置模块下拉显示
            self.textEdit.setText(items[4])
            self.textEdit_2.setText(items[5])
            index3=self.nandu_3.findText(items[6], Qt.MatchFlag.MatchFixedString)
            self.nandu_3.setCurrentIndex(index3)
            logging.info('显示bug详情')

4.4 实现情况

现在bug新增,查询修改没问题。

5、图片管理

bug保存后,上传图片。有删除、图片翻页、查看大图功能

5.1 图片上传

上传图片按钮,触发函数up_image。

对图片大小、格式限制,然后将图片转成Base64格式存入数据库。

python 复制代码
    def up_image(self):
        """上传bug图片"""
        if self.bugid == 0:
            self.ts.xinxi("未获取到bugID,请先选择或者保存bug")
            return

        MAX_IMAGE_SIZE=1.5 * 1024 * 1024  # 图片大小限制(例如:5MB)
        try:
            filename, _=QFileDialog.getOpenFileName(self, "选择图片", "",
                                                    "Image Files (*.jpg *.jpeg *.png *.bmp *.gif)")
            if not filename:        # 未选择图片,退出
                return
            name=filename.split('/')[-1]
            file_size=os.path.getsize(filename)  # 检查文件大小
            if file_size > MAX_IMAGE_SIZE:
                self.ts.xinxi(f'图片大小超过限制({MAX_IMAGE_SIZE / (1024 * 1024)}MB),请上传更小的图片!')
            else:
                img=Image.open(filename)
                img.save(f"_internal/{name}", quality=90)  # 压缩图片
                with open(f"_internal/{name}", 'rb') as image_file:
                    content=base64.b64encode(image_file.read())  # 转换成Base64格式
                os.remove(f"_internal/{name}")

                self.case_db.connect()
                sql=f"INSERT INTO main.image (name, image_bytes,bugid) VALUES (?, ?, ?);"
                if self.case_db.operate_one(sql, (name, content, self.bugid)):
                    self.case_db.over()
                    self.show_image(self.bugid)
                    logging.info('上传bug图片')
                else:
                    self.ts.xinxi("图片上传出错")
        except Exception as e:
            self.ts.xinxi(f"上传出错:{e}")
            logging.error(e)

数据库中,存入的图片。

5.2 图片显示

图片上传后,就触发显示函数。将查询bug的图片,显示到label

首先对图像显示区域进行清理,如果查询到图片,将显示图片、名称、页数。

python 复制代码
    def show_image(self, bugid, number=0):
        """根据bugID,查询bug图片"""
        self.label_image.setText('暂无图片')  # 清空bug图片区域数据
        self.pushButton_10.setVisible(False)  # 删除图片按钮,隐藏
        self.label_15.clear()
        self.label_34.clear()
        self.imageid=None

        self.case_db.connect()
        sql=f"SELECT image_bytes,imageid,name FROM image WHERE bugid=? LIMIT 1 OFFSET {number} "
        value=self.case_db.query_one(sql, (bugid,))
        count=self.case_db.query_one(f"SELECT count(*) FROM image WHERE bugid=? ", (bugid,))
        self.case_db.over()
        if value:                       # 显示图片、数量、名称
            self.imageid=value[1]
            str_encode=base64.b64decode(value[0])  # base64编码对应的解码(解码完字符串)
            pixmap=QPixmap()
            pixmap.loadFromData(str_encode)
            self.label_image.clear()
            scaled_pixmap=pixmap.scaled(self.label_image.size(), Qt.AspectRatioMode.KeepAspectRatio)
            self.label_image.setPixmap(scaled_pixmap)
            self.label_15.setText(f"{number + 1}/{count[0]}")  # 数量
            self.label_34.setText(f"{value[2]}")
            self.pushButton_10.setVisible(True)  # 删除图片按钮,显示
            logging.info('bug图片显示')

5.3 图片上传实现

5.4 大图窗口

点击页面图片,触发大图窗口。

python 复制代码
    def image_clicked(self, event):
        """点击图片,打开图片窗口"""
        if self.imageid:
            self.case_db.connect()
            sql=f"SELECT image_bytes FROM image WHERE imageid=?"
            value=self.case_db.query_one(sql, (self.imageid,))
            self.case_db.over()
            str_encode=base64.b64decode(value[0])
            if not self.child_windows:
                image_max=Image_bug(str_encode)
                self.child_windows.append(image_max)  # 将新打开的窗口添加到子窗口列表
            else:
                self.child_windows[0].update_image(str_encode)  # 已有窗口,更新图片

            logging.info('bug图片,大图窗口')

大图窗口,继承界面设计好的窗口。

使用单例模式,只允许打开一个窗口,再次点击图片就更新窗口图片显示。

对鼠标滚轮进行重写,实现放大缩小图片。

python 复制代码
class Image_bug(QWidget, Ui_imagemax):
    """图片页面"""
    _instance=None

    def __new__(cls, str_encode, parent=None):
        if cls._instance is None:
            instance=super().__new__(cls)
            instance.__init__(str_encode, parent)
            cls._instance=instance  # 保存到类变量以便后续使用
            return instance
        else:
            cls._instance.update_image(str_encode)  # 更新现有实例的图像数据
            return cls._instance

    def __init__(self, str_encode, parent=None):
        if self._instance:  # 避免多次初始化同一个实例
            return
        super().__init__(parent)
        self.str_encode=str_encode
        self.setupUi(self)
        self.init_image()

    def init_image(self):
        """窗口加载图片显示"""
        pixmap=QPixmap()
        pixmap.loadFromData(self.str_encode)
        scene=QGraphicsScene()# 创建图形视图、场景及图像项目
        item=QGraphicsPixmapItem(pixmap)
        scene.addItem(item)
        self.graphicsView.setScene(scene)# 设置视图与场景
        self.graphicsView.wheelEvent=self.wheelEvent_handler    # 重写滚轮事件处理函数
        self.show()

    def update_image(self, new_str_encode):
        """更新窗口图片"""
        self.str_encode=new_str_encode
        self.init_image()   # 重新加载图片数据
        self.activateWindow()  # 激活窗口
        self.raise_()       # 提升窗口至最前面

    def wheelEvent_handler(self, event):
        """滚轮放大缩小图片"""
        zoom_in_factor=1.25
        zoom_out_factor=1 / zoom_in_factor
        delta=event.angleDelta().y() / 120
        if delta > 0:
            factor=zoom_in_factor
        elif delta < 0:
            factor=zoom_out_factor
        else:
            return
        # 获取当前鼠标位置在视图坐标系中的位置
        mouse_pos_scene = self.graphicsView.mapToScene(QPoint(int(event.position().x()), int(event.position().y())))
        # 记录原始视图中心点
        old_center=self.graphicsView.viewport().rect().center()
        # 缩放视图
        self.graphicsView.scale(factor, factor)
        # 计算新的视图中心点,并确保鼠标下的内容不变
        new_center = self.graphicsView.mapFromScene(mouse_pos_scene).toPointF()
        self.graphicsView.centerOn(new_center)

5.5 大图窗口,放大缩小图片实现

相关推荐
郭庆汝5 小时前
pytorch、torchvision与python版本对应关系
人工智能·pytorch·python
思则变8 小时前
[Pytest] [Part 2]增加 log功能
开发语言·python·pytest
漫谈网络9 小时前
WebSocket 在前后端的完整使用流程
javascript·python·websocket
try2find10 小时前
安装llama-cpp-python踩坑记
开发语言·python·llama
博观而约取11 小时前
Django ORM 1. 创建模型(Model)
数据库·python·django
精灵vector13 小时前
构建专家级SQL Agent交互
python·aigc·ai编程
Zonda要好好学习13 小时前
Python入门Day2
开发语言·python
Vertira13 小时前
pdf 合并 python实现(已解决)
前端·python·pdf
太凉13 小时前
Python之 sorted() 函数的基本语法
python
项目題供诗13 小时前
黑马python(二十四)
开发语言·python