<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>

          讓 dogtail 識別 UI 中的元素

          共 5937字,需瀏覽 12分鐘

           ·

          2020-09-15 06:20


          在《利用 dogtail 快速進行 GUI 自動化測試》一節(jié)中,我們實現(xiàn)了一個最基礎的自動化測試程序 - 模擬鼠標點擊按鈕?,F(xiàn)在是時候更進一步了,開始訪問 UI 元素中的信息。


          假設,要獲取按鈕上的文本(例如:用于斷言測試),修改之前的腳本:


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

          from?dogtail.tree?import?*
          import?time

          #?獲取應用程序(根據(jù)程序名稱查找)
          app?=?root.application(appName="Sample02",?description="/home/waleon/workspace/demos/build-Samples-unknown-Debug/Sample02/Sample02")

          #?獲取按鈕(根據(jù)?accessibleName?遞歸查找)
          button?=?app.child('button')

          #?獲取并打印按鈕上的文本
          print('text:',?button.text)

          #?模擬鼠標點擊
          for?i?in?range(3):
          ????button.click()
          ????sleep(1)


          運行之后,你會發(fā)現(xiàn) print() 打印的永遠是 None。這是什么情況,按鈕上分明有內容“test”,但為什么打印不出來?



          這是因為,按鈕元素的信息沒有對外公開,以至于 dogtail 無法識別出來!


          不妨用 sniff 工具查看一下,定位到我們的程序并選擇該按鈕,點擊底下的“Text”選項:



          沒有任何內容,這就說明按鈕的文本是不可訪問的。



          1

          實現(xiàn)可訪問性


          要為 UI 元素提供可訪問性支持,需要使用 Qt 的 Accessibility 技術。即應實現(xiàn) QAccessibleInterface,分發(fā)的形式有兩種:


          • 實現(xiàn)可訪問的插件:子類化 QAccessiblePlugin,重新實現(xiàn)純虛函數(shù) create(),并使用 Q_PLUGIN_METADATA() 宏導出該類(如果想在運行時按需加載,則將接口作為插件分發(fā)比較方便)。

          • 將接口編譯到應用程序中:使用接口工廠 - QAccessible::InterfaceFactory(如果是靜態(tài)鏈接,或不想增加插件的復雜性,則推薦該方式)。


          下面以接口工廠為例,來實現(xiàn)對按鈕文本的可訪問性(要對文本進行操作,需要用到 QAccessibleTextInterface):


          #ifndef?ACCESSIBLE_BUTTON_H
          #define?ACCESSIBLE_BUTTON_H

          #include?
          #include?
          #include?

          class?AccessibleButton?:?public?QAccessibleWidget
          ????????,?public?QAccessibleTextInterface
          {
          public:
          ????explicit?AccessibleButton(QPushButton?*button);
          ????~AccessibleButton();

          ????void?*interface_cast(QAccessible::InterfaceType?t)?Q_DECL_OVERRIDE;
          ????QString?text(QAccessible::Text?t)?const?Q_DECL_OVERRIDE;

          ????QString?text(int?startOffset,?int?endOffset)?const?Q_DECL_OVERRIDE;
          ????void?selection(int?selectionIndex,?int?*startOffset,?int?*endOffset)?const?Q_DECL_OVERRIDE;
          ????int?selectionCount()?const?Q_DECL_OVERRIDE;
          ????void?addSelection(int?startOffset,?int?endOffset)?Q_DECL_OVERRIDE;
          ????void?removeSelection(int?selectionIndex)?Q_DECL_OVERRIDE;
          ????void?setSelection(int?selectionIndex,?int?startOffset,?int?endOffset)?Q_DECL_OVERRIDE;
          ????int?cursorPosition()?const?Q_DECL_OVERRIDE;
          ????void?setCursorPosition(int?position)?Q_DECL_OVERRIDE;
          ????int?characterCount()?const?Q_DECL_OVERRIDE;
          ????QRect?characterRect(int?offset)?const?Q_DECL_OVERRIDE;
          ????int?offsetAtPoint(const?QPoint?&point)?const?Q_DECL_OVERRIDE;
          ????void?scrollToSubstring(int?startIndex,?int?endIndex)?Q_DECL_OVERRIDE;
          ????QString?attributes(int?offset,?int?*startOffset,?int?*endOffset)?const?Q_DECL_OVERRIDE;

          private:
          ????QPushButton?*m_button;
          };

          #endif?//?ACCESSIBLE_BUTTON_H


          由于訪問的是按鈕的文本,所以重點關注 interface_cast()、text() 即可,其他接口可以“忽略”:


          #include?"accessiblebutton.h"
          #include?

          AccessibleButton::AccessibleButton(QPushButton?*button)
          ????:?QAccessibleWidget(button)
          ????,?m_button(button)
          {

          }

          AccessibleButton::~AccessibleButton()
          {

          }

          void?*AccessibleButton::interface_cast(QAccessible::InterfaceType?t)
          {
          ????switch?(t)?{
          ????case?QAccessible::ActionInterface:
          ????????return?static_cast(this);
          ????case?QAccessible::TextInterface:
          ????????return?static_cast(this);
          ????default:
          ????????return?nullptr;
          ????}
          }

          QString?AccessibleButton::text(QAccessible::Text?t)?const
          {
          ????switch?(t)?{
          ????case?QAccessible::Name:
          ????????return?m_button->accessibleName();
          ????case?QAccessible::Description:
          ????????return?m_button->accessibleDescription();
          ????default:
          ????????return?QString();
          ????}
          }

          QString?AccessibleButton::text(int?startOffset,?int?endOffset)?const
          {
          ????Q_UNUSED(startOffset)
          ????Q_UNUSED(endOffset)

          ????return?m_button->text();
          }

          void?AccessibleButton::selection(int?selectionIndex,?int?*startOffset,?int?*endOffset)?const
          {
          ????Q_UNUSED(selectionIndex)
          ????Q_UNUSED(startOffset)
          ????Q_UNUSED(endOffset)
          }

          int?AccessibleButton::selectionCount()?const
          {
          ????return?0;
          }

          void?AccessibleButton::addSelection(int?startOffset,?int?endOffset)
          {
          ????Q_UNUSED(startOffset)
          ????Q_UNUSED(endOffset)
          }

          void?AccessibleButton::removeSelection(int?selectionIndex)
          {
          ?????Q_UNUSED(selectionIndex)
          }

          void?AccessibleButton::setSelection(int?selectionIndex,?int?startOffset,?int?endOffset)
          {
          ????Q_UNUSED(selectionIndex)
          ????Q_UNUSED(startOffset)
          ????Q_UNUSED(endOffset)
          }

          int?AccessibleButton::cursorPosition()?const
          {
          ????return?0;
          }

          void?AccessibleButton::setCursorPosition(int?position)
          {
          ????Q_UNUSED(position)
          }

          int?AccessibleButton::characterCount()?const
          {
          ????return?0;
          }

          QRect?AccessibleButton::characterRect(int?offset)?const
          {
          ????Q_UNUSED(offset)

          ????return?QRect();
          }

          int?AccessibleButton::offsetAtPoint(const?QPoint?&point)?const
          {
          ????Q_UNUSED(point)

          ????return?0;
          }

          void?AccessibleButton::scrollToSubstring(int?startIndex,?int?endIndex)
          {
          ????Q_UNUSED(startIndex)
          ????Q_UNUSED(endIndex)
          }

          QString?AccessibleButton::attributes(int?offset,?int?*startOffset,?int?*endOffset)?const
          {
          ????Q_UNUSED(offset)
          ????Q_UNUSED(startOffset)
          ????Q_UNUSED(endOffset)

          ????return?QString();
          }



          2

          實現(xiàn)接口工廠


          工廠是一個函數(shù)指針,其簽名如下:


          typedef?QAccessibleInterface*?myFactoryFunction(const?QString?&key,?QObject?*);


          該函數(shù)接收一個 QString 和一個 QObject 指針,其中 QString 是標識接口的鍵。QObject 用于傳遞到 QAccessibleInterface,以便它可以保存對其的引用。


          注意:如果 key 和 QObject 沒有對應的 QAccessibleInterface,將返回一個空指針。


          來看一下我們要實現(xiàn)的工廠示例:


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

          ????if?(classname?==?"QPushButton"?&&?object?&&?object->isWidgetType())
          ????????interface?=?new?AccessibleButton(static_cast(object));

          ????return?interface;
          }



          3

          安裝工廠


          完成之后,需要使用 QAccessible::installFactory 對上述工廠進行安裝:


          int?main(int?argc,?char?*argv[])
          {
          ????QApplication?a(argc,?argv);

          ????//?安裝工廠
          ????QAccessible::installFactory(accessibleFactory);

          ????QPushButton?button("test");
          ????QObject::connect(&button,?&QPushButton::clicked,?[&]()?{
          ????????static?int?index?=?0;
          ????????index++;
          ????????button.setText(QString("click?%1").arg(index));
          ????});

          ????//?將被輔助技術識別
          ????button.setAccessibleName("button");
          ????button.setAccessibleDescription("this?is?a?simple?button");

          ????button.resize(300,?200);
          ????button.show();

          ????return?a.exec();
          }



          4

          執(zhí)行自動化


          運行程序,再使用 sniff 工具查看一下,這時已經可以檢測出按鈕的文本了:



          然后重新運行下自動化腳本,文本也可以正常打印了:



          恭喜,這說明 dogtail 已經可以成功識別 UI 中的元素了。


          最后,在自動化測試的過程中,有可能還會有其他元素的信息無法識別,參考上述方式即可。


          ·END·

          瀏覽 149
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  亚洲AV一二三区 | 国产精品美女久久久久久 | 九九九在线观看免费视频 | 国产AV日韩AⅤ亚洲AV中文 | 婷婷狠狠爱 |