<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一個(gè)完整的 GUI 自動(dòng)化測(cè)試程序

          共 6161字,需瀏覽 13分鐘

           ·

          2020-10-02 18:10


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


          以常見的用戶登錄為例,要進(jìn)行自動(dòng)化測(cè)試,需要考慮以下場(chǎng)景:


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

          • 模擬鼠標(biāo)點(diǎn)擊登錄按鈕;

          • 校驗(yàn)錯(cuò)誤提示信息,判斷是否與預(yù)期相符;

          • ......

          • 自動(dòng)生成測(cè)試報(bào)告。


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



          當(dāng)腳本跑完之后,會(huì)生成一個(gè)自動(dòng)化測(cè)試報(bào)告:


          里面包含了所有的測(cè)試結(jié)果,分析起來特別方便!



          1

          登錄界面


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


          #ifndef?WIDGET_H
          #define?WIDGET_H

          #include?
          #include?

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

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

          public:
          ????//?錯(cuò)誤狀態(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


          當(dāng)點(diǎn)擊登錄按鈕后,會(huì)觸發(fā)槽函數(shù) login(),此時(shí)會(huì)校驗(yàn)輸入的密碼,并進(jìn)行錯(cuò)誤提示:


          #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()
          {
          ????//?將被輔助技術(shù)識(shí)別
          ????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ǎn)很關(guān)鍵,需要調(diào)用 setAccessibleName() 為控件設(shè)置可訪問的名稱,這樣才能被輔助技術(shù)所識(shí)別!


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


          //?接口工廠
          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;
          }


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



          2

          自動(dòng)化測(cè)試腳本


          當(dāng)一切準(zhǔn)備就緒,就可以編寫自動(dòng)化測(cè)試腳本了,來看看 autotest.py 都有些什么:


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

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

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

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

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

          • 構(gòu)造測(cè)試集,并生成測(cè)試報(bào)告。


          #!/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")

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

          #?設(shè)置文本
          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):
          ????"""登錄認(rèn)證"""

          ????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__':
          ????#?構(gòu)造測(cè)試集
          ????suite?=?unittest.TestSuite()

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

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

          ????#?執(zhí)行測(cè)試
          ????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)


          看到這里,是不是覺得自動(dòng)化測(cè)試其實(shí)也蠻簡單的,并不像很多人說的那么難!


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



          ·END·

          瀏覽 79
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  俺来俺去俺也射 | 毛片性爱视频 | 亚洲高清成人电影 | 女人操逼视频精品在线播放 | 日本xxxx性爱视频图片 |