1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        一個完整的 GUI 自動化測試程序

        共 6161字,需瀏覽 13分鐘

         ·

        2020-10-02 18:10


        在介紹了 GUI 測試、輔助特性、報表生成等技術點之后,現(xiàn)在可以將它們串聯(lián)起來,實現(xiàn)一個較為完整的自動化測試程序。


        以常見的用戶登錄為例,要進行自動化測試,需要考慮以下場景:


        • 模擬鍵盤輸入密碼(空密碼、錯誤密碼、正確密碼);

        • 模擬鼠標點擊登錄按鈕;

        • 校驗錯誤提示信息,判斷是否與預期相符;

        • ......

        • 自動生成測試報告。


        先來看一下我們的程序,以及自動化腳本執(zhí)行效果:



        當腳本跑完之后,會生成一個自動化測試報告:


        里面包含了所有的測試結果,分析起來特別方便!



        1

        登錄界面


        來看具體的實現(xiàn),登錄界面包含了密碼框、登錄按鈕、提示標簽:


        #ifndef?WIDGET_H
        #define?WIDGET_H

        #include?
        #include?

        class?QLabel;
        class?QLineEdit;
        class?QPushButton;

        class?Widget?:?public?QWidget
        {
        ????Q_OBJECT

        public:
        ????//?錯誤狀態(tài)
        ????typedef?enum?ErrorStatus?{
        ????????NoError?=?0,
        ????????EmptyPassword,
        ????????WrongPassword
        ????}?ErrorStatus;

        ????explicit?Widget(QWidget?*parent?=?Q_NULLPTR);
        ????~Widget()?Q_DECL_OVERRIDE;

        private?Q_SLOTS:
        ????void?login();

        private:
        ????void?initUi();
        ????void?retranslateUi();
        ????void?initConnections();
        ????void?initAccessible();

        private:
        ????QLineEdit?*m_lineEdit;
        ????QPushButton?*m_button;
        ????QLabel?*m_tipLabel;
        ????QMap?m_errorMap;
        };

        #endif?//?WIDGET_H


        當點擊登錄按鈕后,會觸發(fā)槽函數(shù) login(),此時會校驗輸入的密碼,并進行錯誤提示:


        #include?"widget.h"
        #include?
        #include?
        #include?
        #include?

        Widget::Widget(QWidget?*parent)
        ????:?QWidget(parent)
        {
        ????initUi();
        ????retranslateUi();
        ????initConnections();
        ????initAccessible();
        }

        Widget::~Widget()
        {

        }

        void?Widget::initUi()
        {
        ????m_lineEdit?=?new?QLineEdit(this);
        ????m_button?=?new?QPushButton(this);
        ????m_tipLabel?=?new?QLabel(this);

        ????QVBoxLayout?*layout?=?new?QVBoxLayout();
        ????layout->addStretch();
        ????layout->addWidget(m_lineEdit);
        ????layout->addWidget(m_button);
        ????layout->addWidget(m_tipLabel);
        ????layout->addStretch();
        ????layout->setSpacing(15);
        ????layout->setContentsMargins(10,?10,?10,?10);
        ????setLayout(layout);
        }

        void?Widget::retranslateUi()
        {
        ????m_button->setText("Login");

        ????if?(m_errorMap.isEmpty())?{
        ????????m_errorMap.insert(NoError,?"Login?successful");
        ????????m_errorMap.insert(EmptyPassword,?"The?password?should?not?be?empty");
        ????????m_errorMap.insert(WrongPassword,?"Wrong?password");
        ????}
        }

        void?Widget::initConnections()
        {
        ????connect(m_button,?&QPushButton::clicked,?this,?&Widget::login);
        }

        void?Widget::initAccessible()
        {
        ????//?將被輔助技術識別
        ????m_lineEdit->setAccessibleName("passwordEdit");
        ????m_button->setAccessibleName("loginButton");
        ????m_tipLabel->setAccessibleName("tipLabel");
        ????m_lineEdit->setAccessibleDescription("this?is?a?password?line?edit");
        ????m_button->setAccessibleDescription("this?is?a?login?button");
        ????m_tipLabel->setAccessibleDescription("this?is?a?tip?label");
        }

        void?Widget::login()
        {
        ????QString?password?=?m_lineEdit->text();

        ????if?(password.isEmpty())?{
        ????????m_tipLabel->setText(m_errorMap.value(EmptyPassword));
        ????}?else?if?(QString::compare(password,?"123456")?!=?0)?{
        ????????m_tipLabel->setText(m_errorMap.value(WrongPassword));
        ????}?else?{
        ????????m_tipLabel->setText(m_errorMap.value(NoError));
        ????}
        }


        注意:有一點很關鍵,需要調(diào)用 setAccessibleName() 為控件設置可訪問的名稱,這樣才能被輔助技術所識別!


        由于在自動化腳本中需要進行文本校驗,所以應為 QPushButton、QLabel 等 UI 元素實現(xiàn) QAccessibleInterface 接口,然后定義接口工廠并進行安裝:


        //?接口工廠
        QAccessibleInterface?*accessibleFactory(const?QString?&classname,?QObject?*object)
        {
        ????QAccessibleInterface?*interface?=?nullptr;

        ????if?(object?&&?object->isWidgetType())?{
        ????????if?(classname?==?"QLabel")
        ????????????interface?=?new?AccessibleLabel(qobject_cast(object));

        ????????if?(classname?==?"QPushButton")
        ????????????interface?=?new?AccessibleButton(qobject_cast(object));
        ????}

        ????return?interface;
        }


        至于細節(jié)內(nèi)容,可參考《讓 dogtail 識別 UI 中的元素》。



        2

        自動化測試腳本


        當一切準備就緒,就可以編寫自動化測試腳本了,來看看 autotest.py 都有些什么:


        • 通過 root.application() 找到應用程序;

        • 定義枚舉 ErrorStatus,以表示登錄時的錯誤狀態(tài);

        • 定義一個通用函數(shù) set_text(),用于設置輸入框的文本;

          注意:直接調(diào)用 typeText() 只會追加,所以要輸入新內(nèi)容,必須先清空原有內(nèi)容。

        • 繼承 TestCase 類,實現(xiàn)具體的測試用例;

        • 構造測試集,并生成測試報告。


        #!/usr/bin/env?python3
        #?-*-?coding:?utf-8?-*-

        import?unittest
        import?HTMLTestRunner
        from?dogtail.tree?import?*
        import?time
        from?enum?import?Enum,?unique

        app?=?root.application(appName="Sample03",?description="/home/waleon/workspace/demos/build-Samples-unknown-Debug/Sample03/Sample03")

        #?錯誤狀態(tài)
        @unique
        class?ErrorStatus(Enum):
        ????NoError?=?0
        ????EmptyPassword?=?1
        ????WrongPassword?=?2

        #?設置文本
        def?set_text(line_edit,?text):
        ????line_edit.click()
        ????line_edit.keyCombo('a')
        ????line_edit.keyCombo('del')
        ????line_edit.typeText(text)

        class?LoginTestCase(unittest.TestCase):
        ????"""登錄認證"""

        ????def?setUp(self):
        ????????print('==========?begin?==========')
        ????????self.tips?=?{
        ????????????????????????ErrorStatus.EmptyPassword:?'The?password?should?not?be?empty',
        ????????????????????????ErrorStatus.WrongPassword:?'Wrong?password',
        ????????????????????????ErrorStatus.NoError:?'Login?successful'
        ????????????????????}
        ????????self.password_edit?=?app.child('passwordEdit')
        ????????self.login_btn?=?app.child('loginButton')
        ????????self.tip_label?=?app.child('tipLabel')

        ????#?登錄文本內(nèi)容
        ????def?testLoginText(self):
        ????????self.assertEqual(self.login_btn.text,?'Login')

        ????#?密碼為空
        ????def?testEmptyPassword(self):
        ????????set_text(self.password_edit,?'')
        ????????self.login_btn.click()
        ????????self.assertEqual(self.tip_label.text,?self.tips[ErrorStatus.EmptyPassword])

        ????#?密碼不合法(特殊字符)
        ????def?testWrongPassword(self):
        ????????set_text(self.password_edit,?'~!@#$%')
        ????????self.login_btn.click()
        ????????self.assertEqual(self.tip_label.text,?self.tips[ErrorStatus.WrongPassword])

        ????#?密碼正確
        ????def?testCorrectPassword(self):
        ????????set_text(self.password_edit,?'123456')
        ????????self.login_btn.click()
        ????????self.assertEqual(self.tip_label.text,?self.tips[ErrorStatus.NoError])

        ????def?tearDown(self):
        ????????print('==========?end?==========')

        if?__name__?==?'__main__':
        ????#?構造測試集
        ????suite?=?unittest.TestSuite()

        ????#?添加測試用例
        ????suite.addTest(LoginTestCase("testLoginText"))
        ????suite.addTest(LoginTestCase("testEmptyPassword"))
        ????suite.addTest(LoginTestCase("testWrongPassword"))
        ????suite.addTest(LoginTestCase("testCorrectPassword"))

        ????#?報告路徑
        ????date_time?=?time.strftime('%Y%m%d%H%M%S',?time.localtime(time.time()))
        ????report_path?=?'report_'?+?date_time?+?'.html'

        ????#?執(zhí)行測試
        ????with?open(report_path,?'wb')?as?f:
        ????????runner?=?HTMLTestRunner.HTMLTestRunner(
        ????????????stream=f,
        ????????????title='Sample03?unit?test',
        ????????????description='Sample03?report?output?by?HTMLTestRunner.'
        ????????)
        ????????runner.run(suite)


        看到這里,是不是覺得自動化測試其實也蠻簡單的,并不像很多人說的那么難!


        最后,說一下 dogtail 這個東西,雖然文檔資料比較少,但用起來很不錯。綜合來說,值得推薦!



        ·END·

        瀏覽 79
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            已婚女同学下面好紧 | 意大利做爰露性器50部 | 春宵秘戏图啪啪无遮掩 | 欧美人妻综合 | 91久久人澡人妻人人澡人人爽 | 久久精品视频免费 | 日韩99| 97人人爽人人爽人人爽 | 天堂8中文在线 | 午夜日屄|