PyQt5桌面应用开发(21):界面设计结果自动测试(二)

这篇具有很好参考价值的文章主要介绍了PyQt5桌面应用开发(21):界面设计结果自动测试(二)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

PyQt5桌面应用系列

  • PyQt5桌面应用开发(1):需求分析
  • PyQt5桌面应用开发(2):事件循环
  • PyQt5桌面应用开发(3):并行设计
  • PyQt5桌面应用开发(4):界面设计
  • PyQt5桌面应用开发(5):对话框
  • PyQt5桌面应用开发(6):文件对话框
  • PyQt5桌面应用开发(7):文本编辑+语法高亮与行号
  • PyQt5桌面应用开发(8):从QInputDialog转进到函数参数传递
  • PyQt5桌面应用开发(9):经典布局QMainWindow
  • PyQt5桌面应用开发(10):界面布局基本支持
  • PyQt5桌面应用开发(11):摸鱼也要讲基本法,两个字,16
  • PyQt5桌面应用开发(12):QFile与线程安全
  • PyQt5桌面应用开发(13):QGraphicsView框架
  • PyQt5桌面应用开发(14):数据库+ModelView+QCharts
  • PyQt5桌面应用开发(15):界面动画
  • PyQt5桌面应用开发(16):定制化控件-QPainter绘图
  • PyQt5桌面应用开发(17):类结构+QWebEngineView
  • PyQt5桌面应用开发(18):自定义控件界面设计与实现
  • PyQt5桌面应用开发(19):事件过滤器
  • PyQt5桌面应用开发(20):界面设计结果自动测试(一)
  • PyQt5桌面应用开发(21):界面设计结果自动测试(二)

TDD+UI

上一篇简单说了下什么是测试驱动开发(TDD)。这在软件开发行业是比较常规的做法,因为只要不是完美主义强迫症的TDD,对于软件开发的质量管理是很有帮助的,因为TDD把软件开发的质量管理(计划-执行-检查-改进)的循环变得更加可用。

但是加上UI后,这个问题就变得微妙起来了。UI是一种与人相关的内容,最好的做法当然是用人作为测试,常规开发过程中,也的确是依靠人力来进行测试。

那么采用TDD来开发UI,是否能行呢?答案是肯定的。软件行业,如果说有什么事情是不可行的,那么就只有说别的事情是不可行这个事情是不可行的。万物皆虚,万事皆允。软件开发的魅力不就在这里吗?

第二个问题就是,值得这么做吗?也有不多的几篇文章探讨了这个问题。也有两篇正经发表的会议文章写了这个事情。但是文章那么少就说明一个问题,可能意义不大,收益不高。

为什么?

有几个因素限制了TDD开发UI。

首先,UI的重要元素,视觉,难以测试,写形式化测试很难,所以这部分意义不大,比如界面布局,pyqt5的设计工具里面可以用C+R来观察布局,这个预览功能中,还能完美支持界面缩放这些操作,比如界面动画,那个测试难度可想而知,现在能考虑的最大可能就是截图比较像素,然后用某种大模型来判定,但是整这个意义不大,来个儿童就能完成;

其次,UI的完整状态空间特别大,如果要写一个全状态转换的状态机,显然是不可能的,因为排列的状态是界面交互元素个数阶乘量级,所以这样做的可行性也值得怀疑。

最后,UI的设计中,如果采用MVVM或者MVC模式,一般会尽量把功能、数据、交互分开,这样各个部分的单元测试才得以进行,界面的综合功能,还是采用综合测试的比较多。

这么分析下来,思路这篇文章就没多少意义了。但是我都已经写到这里,骑虎难下,还得硬撑下去。

那么先确定几个原则:

  1. 有限测试:把TDD作为开发工具,太难的,太麻烦的不搞,不搞完美主义;
  2. 人工视觉:不测试UI的布局、控件的位置、控件的名字、控件文字标签这些一眼就能看到的东西;
  3. 开发规范:应用场景考虑为刚入职的萌新提供较小的控件开发输入。

确定这个几个原则之后,我们来设计一个场景。

开发任务

任务设计

假设公司来一个小码,他各项技能点满,什么都能干,于是安排小码带一个团队编个PyQt5的工控。小码把其中的一个功能抽象为一个控件,这个控件要换算露点和相对湿度。

此处忽略饱和蒸气压、湿空气、理想气体、多组分气体分压、露点、相对湿度的内容15000字。我们最终只需要知道露点是压力、温度和相对湿度的函数,对应的通过压力、温度和露点也能唯一计算相对湿度。

D = f ( p , T , R ) D = f(p, T, R) D=f(p,T,R)

R = g ( p , T , D ) R = g(p, T, D) R=g(p,T,D)

最终有一个调库大牛编写了一个库,这个库需要CoolProp(pip install CoolProp)
来计算湿空气的热力学特性,提供接口全部使用SI单位,这个库提供两个静态方法(类方法)计算上面两个函数。另外这个库还能通过改变 p p p, T T T, D D D中任意一个来自动更新相对湿度,如果改变相对湿度,则自动改变露点。最后,这个库还能输入一个字符串元组表达四个值。这个库设计的不咋地,但是你懂的,热力学那帮人怎么会编程序……

from CoolProp.CoolProp import HAPropsSI


class RelativeHumidityModelSI:
    """
    HumidAir model with SI units
    temperature/dewpoint: K
    pressure: Pa
    """

    def __init__(self):
        self._pressure: float = 1e5
        self._temperature: float = 300.0
        self._dewpoint: float = 273.0
        self._rh: float = self.rh(self._pressure, self._temperature, self._dewpoint)

    @classmethod
    def rh(cls, p, t, d):
        return round(HAPropsSI("R", "P", p, "T", t, "D", d) * 10000) / 100.0

    @classmethod
    def dp(cls, p, t, r):
        return HAPropsSI("D", "P", p, "T", t, "R", r)

    def _update_rh(self):
        self._rh = self.rh(self._pressure, self._temperature, self._dewpoint)

    def _update_dp(self):
        self._dewpoint = round(self.dp(self._pressure, self._temperature, self._rh / 100.0) * 100) / 100.0

    def str_tuple(self):
        return ("{:.2f}".format(i) for i in [self._pressure, self._temperature, self._dewpoint, self._rh])

    @property
    def pressure(self):
        return self._pressure

    @pressure.setter
    def pressure(self, value):
        self._pressure = value
        self._update_rh()

    @property
    def temperature(self):
        return self._temperature

    @temperature.setter
    def temperature(self, value):
        self._temperature = value
        self._update_rh()

    @property
    def dewpoint(self):
        return self._dewpoint

    @dewpoint.setter
    def dewpoint(self, value):
        self._dewpoint = value
        self._update_rh()

    @property
    def relative_humidity(self):
        return self._rh

    @relative_humidity.setter
    def relative_humidity(self, value):
        self._rh = value
        self._update_dp()

小码的工作

小码把编写这个PyQt5组件的任务交给了,比如说,小机。为了让小机好好干活对他进行合理恰当的压榨,引入了单元测试,让小机写一个能通过测试的组件,至于组件是否好看,那就看小机自己的眼睛了……

小码前面已经学习过QTest类的各种方法,能够点击按钮、键盘输入、移动鼠标,就只需要再学习一下unittest的函数:

unittest函数一览表

Name Function
assertTrue 表达式是否为True。
assertFalse 检查表达式是否为False。
assertIs 等效于assertTrue(a is b)。
assertIsNot 等效于assertTrue(a is not b)。
assertIsInstance 等效于assertTrue(isinstance(obj, cls))。
assertNotIsInstance 与assertIsInstance对应,并非该类的对象。
assertIsNone 等效于assertTrue(obj is None)。
assertIsNotNone 与assertIsNone对应。
assertEqual 运算符’=='意义上的相等。
assertNotEqual 两个对象不相等,含义为’!='。
assertGreater 等效于assertTrue(a > b)。
assertGreaterEqual 等效于assertTrue(a >= b)。
assertLess 等效于assertTrue(a < b)。
assertLessEqual 等效于assertTrue(a <= b),提示信息更有效。
assertAlmostEqual 在一定的允差下的近似相等。
assertNotAlmostEqual 与assertAlmostEqual对应,不在允差范围内。
assertIn 等效于assertTrue(a in b)。
assertNotIn 等价于assertTrue(a not in b)
assertSequenceEqual 序列相等(列表或者元组)
assertCountEqual 测试集合元素的个数。
assertMultiLineEqual 多行字符串相等。
assertTupleEqual 元组相等。
assertListEqual 列表相等。
assertSetEqual 集合相等。
assertDictContainsSubset 测试两个字典的包含性,一个是另外一个的子集。
assertDictEqual 比较两个字典,assertEqual对字典同样是调用此方法。
assertRegex 匹配到正则表达式。
assertNotRegex 不匹配正则表达式。
assertLogs 日志信息被处罚,按照日志等级来判定。
assertWarns 触发特定的 warnClass
assertWarnsRegex 警告消息与regexp吻合。
assertRaises 触发特定的Exception类。
assertRaisesRegex 触发的Exception对应的消息符合正则表达式。
assertNotEquals 废弃,用assertNotEqual替代
assertAlmostEquals 废弃,用assertAlmostEqual替代
assertEquals 废弃,用assertEqual替代
assertNotAlmostEquals 废弃,用assertNotAlmostEqual替代
assertNotRegexpMatches 废弃,用assertNotRegex替代
assertRaisesRegexp 废弃,用assertRaisesRegex替代
assertRegexpMatches 废弃,用assertRegex替代
assert_ 废弃,用assertTrue替代

了解这些之后,小码很快就写出了下面的测试代码:

UI单元测试代码

import unittest
from unittest import TestCase

from HtmlTestRunner import HTMLTestRunner
from PyQt5.QtCore import Qt
from PyQt5.QtTest import QTest
from PyQt5.QtWidgets import QLineEdit, QWidget, QApplication, QComboBox, QPushButton

import relative_humidity_coolprop
from relative_humidity_ui import RelativeHumidityWidget


class RelativeHumidityWidgetConstruction(TestCase):

    def setUp(self) -> None:
        self.app = QApplication([])
        self.widget = RelativeHumidityWidget()
        self.widget.show()
        QTest.qWaitForWindowExposed(self.widget)

    def tearDown(self) -> None:
        self.app.exit(0)

    # four line edit to represent four variables
    def test_interact_components(self):
        self.assertIsInstance(self.widget, QWidget)

        self.assertIsInstance(self.widget.pressureLineEdit, QLineEdit)
        self.assertIsInstance(self.widget.temperatureLineEdit, QLineEdit)
        self.assertIsInstance(self.widget.dewpointLineEdit, QLineEdit)
        self.assertIsInstance(self.widget.relativeHumidityLineEdit, QLineEdit)

        self.assertIsInstance(self.widget.calrh, QPushButton)
        self.assertIsInstance(self.widget.caldp, QPushButton)

        self.assertIsInstance(self.widget.pressureUnit, QComboBox)
        cb: QComboBox = self.widget.pressureUnit
        pressure_units = ['Pa', 'kPa', 'atm', 'bar', 'hPa']
        units = [cb.itemText(i) for i in range(cb.count())]
        self.assertCountEqual(pressure_units, units)
        self.assertListEqual(pressure_units, units)

        self.assertIsInstance(self.widget.temperatureUnit, QComboBox)
        cb: QComboBox = self.widget.temperatureUnit
        temperature_units = ["K", "℃"]
        units = [cb.itemText(i) for i in range(cb.count())]
        self.assertCountEqual(temperature_units, units)
        self.assertListEqual(temperature_units, units)

        self.assertIsInstance(self.widget.dewpointUnit, QComboBox)
        cb: QComboBox = self.widget.dewpointUnit
        temperature_units = ["K", "℃"]
        units = [cb.itemText(i) for i in range(cb.count())]
        self.assertCountEqual(temperature_units, units)
        self.assertListEqual(temperature_units, units)

    def test_initial_values(self):
        self.assertAlmostEqual(1e5, self.widget.pressure, delta=1e-5)
        self.assertAlmostEqual(300.0, self.widget.temperature, delta=1e-5)
        self.assertAlmostEqual(273.0, self.widget.dewpoint, delta=1e-5)
        self.assertAlmostEqual(17.07, self.widget.rh, delta=1e-2)

    def test_value_accessors(self):
        for p, value in zip(
                [self.widget.pressureLineEdit,
                 self.widget.temperatureLineEdit,
                 self.widget.dewpointLineEdit,
                 self.widget.relativeHumidityLineEdit],
                [lambda: self.widget.pressure,
                 lambda: self.widget.temperature,
                 lambda: self.widget.dewpoint,
                 lambda: self.widget.rh]):
            p: QLineEdit
            p.setText("akjdlajf")
            self.assertRaises(ValueError, lambda: value())
            p.setText("1e6")
            self.assertAlmostEqual(1e6, value(), delta=1e-6)

    def test_cal_relative_humidity(self):
        """
        Test calrh button
        :return:
        """
        # setup line edits for pressure, temperature, and dewpoint
        p: QLineEdit = self.widget.pressureLineEdit
        t: QLineEdit = self.widget.temperatureLineEdit
        d: QLineEdit = self.widget.dewpointLineEdit
        p.setText("1e5")
        t.setText("300")
        d.setText("250")
        # click calrh button
        QTest.mouseClick(self.widget.calrh, Qt.LeftButton)
        rh_expected = relative_humidity_coolprop.RelativeHumidityModelSI.rh(1e5, 300, 250)
        # check relative humidity
        self.assertAlmostEqual(rh_expected, self.widget.rh, delta=1e-2)

    def test_cal_dew_point(self):
        """
        Test caldp button
        :return:
        """
        # setup line edits for pressure, temperature, and relative humidity
        p: QLineEdit = self.widget.pressureLineEdit
        t: QLineEdit = self.widget.temperatureLineEdit
        rh: QLineEdit = self.widget.relativeHumidityLineEdit
        p.setText("1e5")
        t.setText("300")
        rh.setText("50")
        # click caldp button
        QTest.mouseClick(self.widget.caldp, Qt.LeftButton)
        dp_expected = relative_humidity_coolprop.RelativeHumidityModelSI.dp(1e5, 300, 0.5)
        # check dew point
        self.assertAlmostEqual(dp_expected, self.widget.dewpoint, delta=1e-2)

        # set unit to degree C
        self.widget.dewpointUnit.setCurrentText("℃")
        QTest.mouseClick(self.widget.caldp, Qt.LeftButton)
        dp_expected = relative_humidity_coolprop.RelativeHumidityModelSI.dp(1e5, 300, 0.5)
        # check dew point return with SI
        self.assertAlmostEqual(dp_expected, self.widget.dewpoint, delta=1e-2)
        self.assertAlmostEqual(dp_expected - 273, float(self.widget.dewpointLineEdit.text()), delta=1e-2)

    def test_change_pressure_unit(self):
        self.assertAlmostEqual(1e5, self.widget.pressure, delta=1e-5)
        self.widget.pressureUnit.setCurrentText("kPa")
        self.assertAlmostEqual(1e5 * 1000, self.widget.pressure, delta=1e-5)
        self.widget.pressureUnit.setCurrentText("atm")
        self.assertAlmostEqual(1e5 * 101325, self.widget.pressure, delta=1e-5)
        self.widget.pressureUnit.setCurrentText("bar")
        self.assertAlmostEqual(1e5 * 1e5, self.widget.pressure, delta=1e-5)
        self.widget.pressureUnit.setCurrentText("hPa")
        self.assertAlmostEqual(1e5 * 1e2, self.widget.pressure, delta=1e-5)
        self.widget.pressureUnit.setCurrentText("Pa")
        self.assertAlmostEqual(1e5, self.widget.pressure, delta=1e-5)

    def test_change_temperature_unit(self):
        self.assertAlmostEqual(300, self.widget.temperature, delta=1e-5)
        self.widget.temperatureUnit.setCurrentText("℃")
        self.assertAlmostEqual(300 + 273, self.widget.temperature, delta=1e-5)
        self.widget.temperatureUnit.setCurrentText("K")
        self.assertAlmostEqual(300, self.widget.temperature, delta=1e-5)

    def test_change_dewpoint_unit(self):
        self.assertAlmostEqual(273, self.widget.dewpoint, delta=1e-5)
        self.widget.dewpointUnit.setCurrentText("℃")
        self.assertAlmostEqual(273 + 273, self.widget.dewpoint, delta=1e-5)
        self.widget.dewpointUnit.setCurrentText("K")
        self.assertAlmostEqual(273, self.widget.dewpoint, delta=1e-5)


if __name__ == '__main__':
    # unittest.main()
    suite = unittest.TestLoader().loadTestsFromTestCase(RelativeHumidityWidgetConstruction)
    runner = HTMLTestRunner(verbosity=2, output='report', report_name='report', add_timestamp=True,
                            combine_reports=True)
    # unittest.TextTestRunner(verbosity=2).run(suite)
    runner.run(suite)

这里为了方便小机编写的空间在其他成立使用,首先小码需要规定那些这个控件是QWidget的子类,还必须提供一些接口,比如获得压力、温度、露点、相对湿度(全部采用SI单位),另外,为了使用方便,还要规定提供表达单位的空间,必须是QComboBox,提供几种单位(压力和温度单位),最后要求设置的数值不合理的时候,要触发ValueError(这个实在太牵强……因为小码也是个渣渣),最后就是改变一个量,对应的相对湿度(或者露点)的变化。

写完这个,小码算是松了一口气。压力给到了小机这边。

控件代码

小机用尽了洪荒之力,反复徘徊于单元测试错误的重压之下,最终提交了一个代码:

import sys

from PyQt5 import uic
from PyQt5.QtWidgets import QWidget, QLineEdit, QApplication, QComboBox, QPushButton

from relative_humidity_coolprop import RelativeHumidityModelSI


def temperature_SI(val, unit):
    """
    :param val:
    :param unit:  K, degC
    :return: val in K
    """
    if unit == "K":
        return val
    if unit == "℃":
        return val + 273
    raise ValueError(f"{unit} should be K or ℃")


def pressure_SI(val, unit):
    if unit == "Pa":
        return val
    if unit == "kPa":
        return val * 1e3
    if unit == "atm":
        return val * 101325
    if unit == "bar":
        return val * 1e5
    if unit == "hPa":
        return val * 100
    raise ValueError(f"{unit} should be Pa, kPa, atm, bar, or hPa")


class RelativeHumidityWidget(QWidget):
    def __init__(self, parent=None):
        self.model = RelativeHumidityModelSI()
        super(RelativeHumidityWidget, self).__init__(parent)
        uic.loadUi("relative_humidity.ui", self)

        self.pressureLineEdit: QLineEdit
        self.pressureUnit: QComboBox
        self.temperatureLineEdit: QLineEdit
        self.temperatureUnit: QComboBox
        self.dewpointLineEdit: QLineEdit
        self.dewpointUnit: QComboBox
        self.relativeHumidityLineEdit: QLineEdit
        self.calrh: QPushButton
        self.caldp: QPushButton

        p, t, d, r = self.model.str_tuple()
        self.pressureLineEdit.setText(p)
        self.temperatureLineEdit.setText(t)
        self.dewpointLineEdit.setText(d)
        self.relativeHumidityLineEdit.setText(r)

        self.calrh.clicked.connect(self.calculate_rh)
        self.caldp.clicked.connect(self.calculate_dp)

    def calculate_dp(self):
        self.model.pressure = self.pressure
        self.model.temperature = self.temperature
        self.model.relative_humidity = self.rh
        p, t, d, r = self.model.str_tuple()
        if self.dewpointUnit.currentText() == "℃":
            d = "{:.2f}".format(self.model.dewpoint - 273)
        self.dewpointLineEdit.setText(d)

    def calculate_rh(self):
        self.model.pressure = self.pressure
        self.model.temperature = self.temperature
        self.model.dewpoint = self.dewpoint
        p, t, d, r = self.model.str_tuple()
        self.relativeHumidityLineEdit.setText(r)

    @property
    def temperature(self):
        value: str = self.temperatureLineEdit.text()
        unit: str = self.temperatureUnit.currentText()
        return temperature_SI(float(value), unit)

    @property
    def pressure(self):
        value: str = self.pressureLineEdit.text()
        return pressure_SI(float(value), self.pressureUnit.currentText())

    @property
    def dewpoint(self):
        value: str = self.dewpointLineEdit.text()
        unit: str = self.dewpointUnit.currentText()
        return temperature_SI(float(value), unit)

    @property
    def rh(self):
        value: str = self.relativeHumidityLineEdit.text()
        return float(value)


if __name__ == '__main__':
    app = QApplication([])
    widget = RelativeHumidityWidget()
    widget.show()

    sys.exit(app.exec_())

界面设计,当然是拖几个控件,搞搞布局就行。

PyQt5桌面应用开发(21):界面设计结果自动测试(二)

对应的ui文件也很简单。

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
    <class>Form</class>
    <widget class="QWidget" name="Form">
        <property name="geometry">
            <rect>
                <x>0</x>
                <y>0</y>
                <width>696</width>
                <height>185</height>
            </rect>
        </property>
        <property name="sizePolicy">
            <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
                <horstretch>1</horstretch>
                <verstretch>0</verstretch>
            </sizepolicy>
        </property>
        <property name="windowTitle">
            <string>Form</string>
        </property>
        <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0">
            <item>
                <layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0" rowminimumheight="1,1,1,1,0">
                    <item row="0" column="0">
                        <widget class="QLabel" name="label">
                            <property name="text">
                                <string>Pressure</string>
                            </property>
                        </widget>
                    </item>
                    <item row="2" column="1">
                        <widget class="QLineEdit" name="dewpointLineEdit"/>
                    </item>
                    <item row="0" column="1">
                        <widget class="QLineEdit" name="pressureLineEdit"/>
                    </item>
                    <item row="1" column="1">
                        <widget class="QLineEdit" name="temperatureLineEdit"/>
                    </item>
                    <item row="2" column="2">
                        <widget class="QComboBox" name="dewpointUnit">
                            <item>
                                <property name="text">
                                    <string>K</string>
                                </property>
                            </item>
                            <item>
                                <property name="text">
                                    <string></string>
                                </property>
                            </item>
                        </widget>
                    </item>
                    <item row="3" column="1">
                        <widget class="QLineEdit" name="relativeHumidityLineEdit"/>
                    </item>
                    <item row="0" column="2">
                        <widget class="QComboBox" name="pressureUnit">
                            <item>
                                <property name="text">
                                    <string>Pa</string>
                                </property>
                            </item>
                            <item>
                                <property name="text">
                                    <string>kPa</string>
                                </property>
                            </item>
                            <item>
                                <property name="text">
                                    <string>atm</string>
                                </property>
                            </item>
                            <item>
                                <property name="text">
                                    <string>bar</string>
                                </property>
                            </item>
                            <item>
                                <property name="text">
                                    <string>hPa</string>
                                </property>
                            </item>
                        </widget>
                    </item>
                    <item row="2" column="0">
                        <widget class="QLabel" name="label_5">
                            <property name="text">
                                <string>Dew Point</string>
                            </property>
                        </widget>
                    </item>
                    <item row="1" column="0">
                        <widget class="QLabel" name="label_2">
                            <property name="text">
                                <string>Temperature</string>
                            </property>
                        </widget>
                    </item>
                    <item row="1" column="2">
                        <widget class="QComboBox" name="temperatureUnit">
                            <item>
                                <property name="text">
                                    <string>K</string>
                                </property>
                            </item>
                            <item>
                                <property name="text">
                                    <string></string>
                                </property>
                            </item>
                        </widget>
                    </item>
                    <item row="3" column="0">
                        <widget class="QLabel" name="label_7">
                            <property name="text">
                                <string>RH</string>
                            </property>
                        </widget>
                    </item>
                    <item row="3" column="2">
                        <widget class="QLabel" name="label_3">
                            <property name="text">
                                <string>%</string>
                            </property>
                        </widget>
                    </item>
                </layout>
            </item>
            <item>
                <layout class="QHBoxLayout" name="horizontalLayout">
                    <item>
                        <widget class="QPushButton" name="calrh">
                            <property name="text">
                                <string>Relative Humidity</string>
                            </property>
                        </widget>
                    </item>
                    <item>
                        <widget class="QPushButton" name="caldp">
                            <property name="text">
                                <string>Dew Point</string>
                            </property>
                        </widget>
                    </item>
                </layout>
            </item>
            <item>
                <spacer name="verticalSpacer">
                    <property name="orientation">
                        <enum>Qt::Vertical</enum>
                    </property>
                    <property name="sizeType">
                        <enum>QSizePolicy::MinimumExpanding</enum>
                    </property>
                    <property name="sizeHint" stdset="0">
                        <size>
                            <width>0</width>
                            <height>0</height>
                        </size>
                    </property>
                </spacer>
            </item>
        </layout>
    </widget>
    <resources/>
    <connections/>
</ui>

测试报告

最终就能够运行python relative_humidity_unittest.py得到测试报告:

PyQt5桌面应用开发(21):界面设计结果自动测试(二)

总结

通过完整走一遍TDD驱动的UI开发,小码和小机有几个体会。文章来源地址https://www.toymoban.com/news/detail-487914.html

  1. TDD对于UI设计有至少5毛钱的作用,通过编写单元测试,对单一控件的设计概念到设计实现由很好的推动作用;
  2. 看起来不是很好处理设计变更的……因为测试算例多了之后,跟踪变化将会消耗大量的注意力;
  3. 有单元测试的UI开发确实挺轻松,这样设计的工作就被很好地分离为功能设计和功能实现,对于某些场景的软件开发组织应该有很高的价值;
  4. TDD驱动UI设计,真的要注意的是,界面的正式设计文档、UI/UX设计的结果与测试用例之间的一致性问题。
  5. 行为测试的算例编写实际上进行的是设计工作,这一点必须要弄很清楚,所以编写UI测试用例不应该有一些一蹴而就、三两下就行的奢望,这是设计工作。

到了这里,关于PyQt5桌面应用开发(21):界面设计结果自动测试(二)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 实习记录(5)——PyQT5界面设计及交互

    首先按照甲方PPT上给的界面做了,在写内部逻辑的时候发现有不少问题,没考虑到使用者的感受,甚至我觉得根本用不了。于是我和小哥讨论了一下之后,我按照我的想法做了一个新的页面出来,能实现需求的同时,让使用的人体验更好也更直观。 昨天安装成功了PyQT5,今天

    2023年04月24日
    浏览(31)
  • 基于PyQt5的桌面图像调试仿真平台开发(8)锐化

    基于PyQt5的桌面图像调试仿真平台开发(1)环境搭建 基于PyQt5的桌面图像调试仿真平台开发(2)UI设计和控件绑定 基于PyQt5的桌面图像调试仿真平台开发(3)黑电平处理 基于PyQt5的桌面图像调试仿真平台开发(4)白平衡处理 基于PyQt5的桌面图像调试仿真平台开发(5)亮度处理 基于PyQt5的桌

    2024年02月12日
    浏览(29)
  • 使用PYQT5设计登录界面并实现界面跳转

    目录   1 UI登录界面的布局 2 UI登录界面布局对应的代码 3 登录界面和界面跳转完整代码 4 跳转界面代码函数和优化界面代码 5 最终效果        其中, 欢迎使用 XXXX 软件管理员密码 使用的是左边功能的 label 类、 登录 使用的是左边功能的 Push Button 类、 管理员和密码的输入

    2024年02月02日
    浏览(41)
  • 基于PyQt5的桌面图像调试仿真平台开发(10)色彩矩阵

    基于PyQt5的桌面图像调试仿真平台开发(1)环境搭建 基于PyQt5的桌面图像调试仿真平台开发(2)UI设计和控件绑定 基于PyQt5的桌面图像调试仿真平台开发(3)黑电平处理 基于PyQt5的桌面图像调试仿真平台开发(4)白平衡处理 基于PyQt5的桌面图像调试仿真平台开发(5)亮度处理 基于PyQt5的桌

    2024年02月13日
    浏览(21)
  • 基于PyQt5的桌面图像调试仿真平台开发(1)环境搭建

    基于PyQt5的桌面图像调试仿真平台开发(1)环境搭建 基于PyQt5的桌面图像调试仿真平台开发(2)UI设计和控件绑定 基于PyQt5的桌面图像调试仿真平台开发(3)黑电平处理 基于PyQt5的桌面图像调试仿真平台开发(4)白平衡处理 基于PyQt5的桌面图像调试仿真平台开发(5)亮度处理 基于PyQt5的桌

    2024年02月12日
    浏览(27)
  • Yolov5(v5.0) + pyqt5界面设计

     2.1 添加QtDesigner  Qt Designer 是通过拖拽的方式放置控件,并实时查看控件效果进行快速UI设计 位置 内容 name 可以随便命名,只要便于记忆就可以,本次采取通用命名:Qt Designer Program designer.exe路径,一般在python中.Librarybindesigner.exe Arguments 固定格式,直接复制也可: $FileDir

    2024年04月15日
    浏览(36)
  • 基于PyQt5的桌面图像调试仿真平台开发(3)黑电平处理

    基于PyQt5的桌面图像调试仿真平台开发(1)环境搭建 基于PyQt5的桌面图像调试仿真平台开发(2)UI设计和控件绑定 基于PyQt5的桌面图像调试仿真平台开发(3)黑电平处理 基于PyQt5的桌面图像调试仿真平台开发(4)白平衡处理 基于PyQt5的桌面图像调试仿真平台开发(5)亮度处理 基于PyQt5的桌

    2024年02月11日
    浏览(42)
  • 基于PyQt5的桌面图像调试仿真平台开发(13)图像边缘显示

    基于PyQt5的桌面图像调试仿真平台开发(1)环境搭建 基于PyQt5的桌面图像调试仿真平台开发(2)UI设计和控件绑定 基于PyQt5的桌面图像调试仿真平台开发(3)黑电平处理 基于PyQt5的桌面图像调试仿真平台开发(4)白平衡处理 基于PyQt5的桌面图像调试仿真平台开发(5)亮度处理 基于PyQt5的桌

    2024年02月16日
    浏览(31)
  • 基于PyQt5的桌面图像调试仿真平台开发(11)清晰度测试

    基于PyQt5的桌面图像调试仿真平台开发(1)环境搭建 基于PyQt5的桌面图像调试仿真平台开发(2)UI设计和控件绑定 基于PyQt5的桌面图像调试仿真平台开发(3)黑电平处理 基于PyQt5的桌面图像调试仿真平台开发(4)白平衡处理 基于PyQt5的桌面图像调试仿真平台开发(5)亮度处理 基于PyQt5的桌

    2024年02月12日
    浏览(29)
  • PyQt5下界面设计, 无边框加阴影界面, 鼠标左键移动事件

            本人小白, 网罗各个网页与资源学习总结的内容, 设置界面无边框且留有阴影, 且鼠标左键可以拖动界面的方法.         首先我们寻找一个模板进行学习演示, 例如腾讯会议的界面:         本人会仿照这个界面进行演示说明, 包括各种样式(你看到就是赚到)      

    2023年04月09日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包