PythonのデスクトップGUIテスト。 Yandexでの講義

AquantiaのVasily Ryabov vasily-v-ryabovは 、Pythonを使用してデスクトップインターフェイスをテストする方法を説明しています。 この講義では、pywinautoライブラリのオープンソースツールとアクセシビリティ技術のサポートについて学びます。 ビデオと復号化は主にWindows用のソフトウェアをテストしている人を対象としていますが、著者はLinuxとmacOSについても少し話しています。





-皆さんこんにちは。 デスクトップGUIテストの自動化に関する技術レポートがあります。 これは純粋にオープンソースに関するものであり、有料のものについては言及しません。 使用できるほとんどすべてのオープンソースソリューションが言及されます。



私は完全なレビューと比較のふりをしませんが、私が使用したものと私たちの小さなコミュニティが取り組んでいるものを教えます。







デスクトップGUI自体のタスクは、一般的な標準がないため、Webよりも複雑です。 たとえば、いくつかの制御アクションを送信するために、多少簡単に解決できますが、それほど簡単ではありません。



また、一部の情報を確認するために、コントロールからテキストを取得できる必要がありますが、これだけではありません。 また、どこをクリックするだけでなく、どこをクリックするかを正確に知る必要があります。







3つの一般的なアプローチがあります。 最も信頼性の低い-彼らはハードコードされた座標を取り、空に指でどこかに突っ込んだ。 一度、画面解像度が変更され、テーマが変更され、ウィンドウサイズ、別の場所で開かれたウィンドウ、他の何か、すべてが行って泳ぎました。 サポートすることは不可能です。手でテストする方が簡単です。



2番目のアプローチはより信頼性がありますが、パターン認識に基づいてそれほど安定していません。 現在、いくつかの人気を得ているツールがあります。 これはテキスト認識に関するものではありません。 むしろ、画面上で同様の正方形または長方形を探して、そこをクリックするだけです。 それらの中で最も人気のあるものはシクリです。 Lackeyは純粋なPythonのアナログです。 メインレポートはPythonのツールに関するものですが、他の言語についても言及します。



最後に、最も信頼性が高く最速のアプローチは、アクセシビリティ技術に基づいています。 残念ながら、それは常に適用できるわけではありません-行く場所がまったくない場合は、何らかの形でイメージを認識することができます。







アクセシビリティ技術とは何ですか? 基本的に、それらについてはすでに聞いています:古き良きWin32 APIとMicrosoftの最新テクノロジー、それほど新しいものではありません-MS UIオートメーションは、Win32 APIを部分的に含みますが、階層が異なり、それほど単純ではありません。 それ自体でより多くのアプリケーションをサポートします。



確かにあなたの多くは、Spy ++などのオブジェクトインスペクタを使用したことがあります。 これは自動化の親友です。 UIオートメーションには独自のオブジェクトインスペクターがあります。これにより、ウィンドウの階層を表示し、そこにツリーがどのように配置されているかを調べることもできます。 これはInsect.exeで、Windows SDKのProgram Filesフォルダーにあります。 すべてがインストールされていれば、見つけることができます。



LinuxとMacにはまだ技術がありますが、それらについては1つのスライドで説明します。 それらは存在し、それらを使用するツールさえあります。



最初に、古き良きWin32 APIのオープンソースツールについて説明しましょう。 彼は年老いていますが、彼は頭がいいです。







AutoItやAutoHotkeyなどのかなり有名なツールがあります。 それぞれに独自のスクリプト言語があり、これは少し普遍的ですが、人気があり、長い間市場に出回っています。 同じAutoItが、何かを提供するために、開発者によって管理タスク、自動化のために配置される可能性が高くなります。 それにもかかわらず、多くのテスターは、特にGUIテスト用に適合させました。



かつて、pywinautoというPythonライブラリに出会いました。 それから私はAutoItまたはAutoHotkeyについて知りませんでした。 それは純粋なPythonで、とても美しいインターフェースで、ライセンスも便利です。 かつて、私は自分のタスクにpywinautoを選択しました。







説明のために、pywinautoでコードを書くのがいかに簡単かという例を示します。 アプリケーションを起動するだけで、オブジェクトの属性としてメインウィンドウの名前に戻ります。 クラスのメンバーとして、私たちは振り返ります。 次に、同じコンボボックス(横に[色]が表示されているもの)に切り替えます。 テキストからすべてを選択します。 ボタンをクリックして、ウィンドウが表示されなくなった、閉じることを制御します。



かなり快適に見えますが、どのように機能するかを詳しく見ていきます。 この単純な外部概念の下には、多くのものがあります。







まず、話について少し。 このライブラリは2006年に登場しましたが、2010年までは著者のマークマクマホンによって開発されました。 2010年に使用を開始しましたが、サポートが終了しました。 それが起こった、これは人生です。 その後、アプリケーションで64ビットに切り替えたところ、最初のテストを作成したときに、すでに64ビットをテストする必要があることがわかりました。 私は自分で図書館の内部を振る必要がありました。



私たちはしばらくの間インテルで内部クローンを使用しましたが、このクローンと一緒に非常に長い間住んでいましたが、非常に安定しており、2014年の終わりまでに、プロジェクト自体が実現しなかったため、これをオープンソースに戻す必要があることを理解するようになりました。 私は彼を復活させなければなりませんでした。



同時に、2番目から3番目のPythonに移植されました。 すべての官僚的な手順の後、彼らはバージョン0.5.4の新しいメジャーリリースをリリースし、私は自由な時間にこのプロジェクトに取り組み続けました。



今年の秋にリリースされた次のメジャーリリースでは、MS UIオートメーションテクノロジ、つまりはるかに広範なアプリケーションがサポートされました。 彼はすでに開発者コミュニティを去っています。 私たちはこのライブラリを引き続きサポートしますが、他のプラットフォームをサポートするための多くの計画があります。







UIオートメーションテクノロジーについて。 おそらくあなたが聞いた名前。 これは純粋な.NETテクノロジーだと考える人もいます。 これは実際にはそうではありません。 .NETにはラッパーがあります。 また、このライブラリのコアであるクライアント部分には、ネイティブCOMインターフェイスがあります。



同じC#には他のオープンソースツールがあり、.NETを通じてこのテクノロジーを使用しています。 これはかなり前から存在していたTestStack.Whiteと、Seleniumスタイルのインターフェースを提供するより若いWinium.Desktopです。



C#を希望する場合は、両方のライブラリを使用できます。 私はかつて、explorer.exeから同じYandexまたはGoogle Driveにドラッグアンドドロップを使用してファイルをドラッグするように生徒に指示しました。 そして、Whiteの助けを借りて、Winiumの助けを借りて、彼らは普通に対処しました。どちらのツールも非常に使いやすいです。 唯一のことは、C#のユーザーが将来どのようにクロスプラットフォームになるのかが明確ではないということです。



pywinautoライブラリは、その中間でこれまでのところ人気があり、すべてが先を行っています。







UIオートメーションは、完全に完璧であればすべての人が使用します。 残念ながら、Win32 APIよりも優れていますが、まだ多少面倒です。 さらに、.NETラッパーを使用することはあまり効果的ではない場合があります。これは、一部のコントロールを見逃すことがあるためです。 めったに再現されないが、よく知られているバグがあります。



さらに、COMインターフェイスは、ネイティブではありますが、標準ではありません。 これは、MS ExcelやWordのようなIDispatchではありません。 カスタムインターフェイスが使用されます。



そしてもちろん、誰もがテクノロジーを使えるわけではありません。 Javaには独自のウィンドウシステムがあります。 私の意見では、GTK +。 一般に、Windowsにはアクセシビリティ技術がありません。 Java、特にGTK +に関しては、これは市場の80%ではありません。 したがって、幅広いアプリケーションをカバーできます。







かつて、.NETの下からUIオートメーションを使用しようとしました。 .NETで直接動作するPythonインタプリタ「iron Python」がありますが、それだけでは完全ではありません。ArrayListには不快なバグがあるため、小さなC#ライブラリを使用してそれをざっと見る必要がありました。 さらに、プロジェクトはしばらくの間死にかけていました。 「鉄のパイソン」について話すと、彼は再び復活したようです。 一般に、オプションではありません。



しかし、CPythonと呼ばれる純粋なPythonのソリューションがありました。 これはPythonであり、python.orgまたはActiveState Pythonで誰でも利用できます。



Com Typesと呼ばれるサードパーティの非標準Pythonプロジェクトがあります。 これらのカスタムCOMインターフェイスをサポートします。 彼は本当に私たちを救い、たくさんのことをさせてくれました。 もちろん、彼には限界があります。 どうやら、深くて小さいが、不快で見つけにくいバグがあり、カスタムコントロールを処理できるライブラリから関数を読み込むことができません。 将来的には誰かがこの問題を解決するかもしれませんが、誰かを期待することは困難です。







それにもかかわらず、すべての標準コントロールをサポートできます。 pywinautoコードに加える必要のある変更:低レベルレイヤーの概念を導入し、Win32 APIサポートを残し、別のバックエンドと呼ばれるものを追加しました-uia。



最初に、唯一の違いは、アプリケーションをアプリケーションオブジェクトとして実行するだけでなく、異なるバックエンドをサポートすることを示すことです。 そしてそれだけです。 その後、ほとんどすべてが同じです。 そうではありません-ウィンドウ階層は、アクセシビリティ技術によって若干異なります。 しかし、基本的にアプローチは同じです。







このアプローチは何ですか? まず、出発点が必要です。そこから踊ります。 これはアプリケーションオブジェクトです。 起動して、すでに実行中のアプリケーションに接続できます。 接続できる基準はさまざまです:exeによって、いくつかのウィンドウによって。 より多くの基準がある場合がありますが、ここでは例のみを示します。



一部のデスクトップアプリケーション、特にWindows 10では、ウィンドウの階層でさえ、たとえば電卓などの複数のプロセスにまたがることがあります。 この階層を迂回するには、ルート要素であるデスクトップオブジェクトから取得して踊る方が便利な場合があります。これは、この目的のために最近実装したものです。



アプリケーションまたはルート要素から、ウィンドウ仕様を作成できます。 これは単なるルートコンセプトであり、pywinautoインターフェースデバイスのまさに基盤です。 ウィンドウの仕様-説明するだけです。 存在しないか、画面上に存在しない可能性があります。 そして、この説明からコントロールを探すことができます。



それを見つけたら、Wrapperオブジェクトを作成します。これは、実際に存在するボタン、実際に存在する編集ボックス、それを引っ張って制御できる触手のある緑色のものに結び付けられたラッパーです。



どのような種類の説明を作成できるかについて詳しく説明します。







最初の最も簡単な方法は、アプリケーションからメインウィンドウの名前で移動し、次にボタンの名前で移動するだけです。 ただし、ポイントごとの属性によるオブジェクトへのアクセスには制限があります。 テキストがロシア語または中国語で書かれている場合-どうすればよいですか? 通常のPython辞書としてキーアクセスを使用する必要があります。 それはほとんど同じです。



完全に正確に言うと、これは3番目のオプションと同等です。 最初のオプションでは、属性によるアクセスにスペースを入力できないため、ウィンドウの検索はタイプミスに対してほぼ正確です。 そのため、より詳細に使用できます-詳細な説明を作成します。 複数の基準が存在する場合がありますが、以下に示すように、一度に2つ以上の基準が設定されているため、テキストは同じであり、同じ種類のコントロールがあります。 コントロールのタイプを明示的に指定すると、より速く動作します。 これは、より速いコードを書くためのちょっとしたトリックです。







このキッチン全体はどのように機能しますか? ウィンドウの仕様から、何らかの形でラッパーを作成する必要があります。 最初の青い線と2番目の線はまったく同じように機能し、同じことを行います。Wrapperオブジェクトの作成はPythonによって隠されています。 Pythonはまだこれを行っていません。



クリックせずにこれを行い、そのようなステートメントを以下に記述すると、わずかに異なるものが返されます。 最初のオプションはウィンドウ仕様を返し、2番目のオプションはWrapperを返します。これを使用して作業できます。 延期するとき、テストを開発するとき、Wrapperオブジェクトを明示的に呼び出して、それが持つメソッド、コントロールでできることを確認するのが便利です。 プロダクションコードでは、混乱しないように、これらのWrapperオブジェクトを削除できます。 その後、それらは自動的に作成され、Clickメソッドまたは他の何かが呼び出されます。







これに先立ち、どのクラスのどのオブジェクトを作成するかを明示的に示していませんでした。 Pywinautoは、目的のクラスを自動的に検索し、目的のラッパーの目的のクラスを作成できます。 これは、Pythonのメタクラスを通じて機能します。 別の黒魔術パイソン。 これは、レジストリパターンと呼ばれるオブジェクトのレジストリです。 いくつかのクラスレジストリを保存します。 使用するコントロールのタイプに応じて-通常はクラス名行です-クラスのオブジェクトを作成できます。



HwndWrapperという基本クラスを呼び出すと、2番目のブランチnew_classは目的のWrapperを自動的に検索し、このクラスのオブジェクトを作成します。 そして、派生クラスを作成する場合、単に明示的に作成します。 必要に応じて、指定したクラスを明示的に作成できますが、ほとんどの場合、これは必要ありません。これにより、プログラミング経験がほとんどない、またはまったくないユーザーの入力しきい値がわずかに減少します。







これは、HwndWrapperから派生したクラスの実装方法です。 これは、受け入れられるクラス名のタイプを示します。 これは、標準のComboBoxおよびWindowsFormsのサポートです。 次に、コントロールをプルできるメソッドがあります。







explorer.exeからYandex.Diskにドラッグする例を示しますが、Yandex.Diskはありません。 この例はそれほど簡単ではありません; Win32 APIを使用するエクスプローラーでは、すべてを実行できるわけではありません。 pywinautoフォルダーを開いたので、ファイルをクリックして、そのプロパティを確認したいと思います(ケーススタディ)。







実行するには、pywinautoにそれほど多くの行は必要ありません。 必要なウィンドウタイトルを持つエクスプローラーに接続します。 アクティブなウィンドウとして切り替えます。 次は、ファイルがリストされているリストです。



遅延初期化があるため、CPU使用率が低下するまで待機する関数を追加する必要もあります。これについては後で詳しく説明します。 また、1行追加します。



right_click_inputを実行し、クリックして、コンテキストメニューのプロパティメニューを1行で呼び出します。 次に、プロパティはexplorer.exeではなく別のプロセスで開かれるため、デスクトップオブジェクトを介してプロパティに移動し、ダイアログを取得して、[キャンセル]ボタンをクリックするだけです。 これにはすべて非常に時間がかかります。



結果。







ちょっとした魔法。 スーパービジョン。







コントロールと通信できる識別子はどこで入手できますか? メインウィンドウがあり、タイトルがあり、表示されているとします。 その後、すべての識別子を印刷できます。 いくつかのものは、Pythonコード、独自のスクリプトに実際に貼り付けることができます。



たとえば、ComboBox属性には、ComboBoxと境界サイズのComboBoxの2つの名前が推奨されています。 左側は単なる静的コントロールです。







この呪文を唱えるには5つの方法があります。 テキスト、[OK]ボタンで簡単に適用できます。 これは単にOKであるだけでなく、ある種の碑文だけでなく、ボタンでもあると言えます。 多くのボタンがあり、すべてが同じテキストを持っている場合、インデックスを単に参照します:button1、button2など。コントロールが動的な場合、EditBox、その中のテキストは絶えず変化し、そこに何かを入力して削除します。次に静的で、毎回同じ方法でコントロールにアクセスします。 Staticは、左側のラベルまたはTextBoxにすることができます。 タブコントロールおよびリストの他の要素の場合、コントロールのタイプおよびタブの1つの名前によって適用できます。 内部テキストもこの名前に参加できます。 このようなスキームは、コントロールへのアクセス方法を完全にカバーしています。







非常に詳細な方法があります-Windowメソッドを呼び出してWindows仕様を作成するとき。 仕様の作成方法は関係ありません。 それに応じて、有効または表示などの単純な状態を切り替えるために、表示されるのを待つか、表示が消えるのを待つことができます。



同じエクスプローラーにとって便利なもう1つの便利な点は、CPUの負荷が低下するまで待つことです。 システム全体ではなく、この特定のプロセスのためです。 Win32 APIにはこのようなものがありますが、このような単純なラッパーを使用して実装しました。 示されたプロセスのプロセッサ負荷が10%を下回ると予想され、10秒以内にこれが発生しない場合は、例外がスローされます。



また、期待のために、例外をスローせず、単にtrueまたはfalseを返す、存在する、表示するなどのメソッドがあります。



理解できるように思えるかもしれませんが、デスクトップ自動化のトピックは複雑であり、多くの落とし穴があります。







GUIテストを作成するにはある程度の経験が必要です。 プログラミング経験が非常に望ましい。



ライブラリに依存しない一般的な問題について。 pywinautoと他のライブラリの両方でそれらを満たすことができます。



多くの場合、グラフィックテストにはアクティブなデスクトップが必要です。 システムをロックして昼食に出た場合、アクティブなデスクトップはありません。 リモートデスクトップに移動して最小化した場合、再びアクティブなデスクトップはありません。 そして、展開されている場合、それは。 スクリプトを実行し、昼食をとりながら何かをテストします。 リモートデスクトップの場合、最小化することはできませんが、たとえば、フルスクリーンモードを終了してウィンドウモードのままにし、スクリプトを実行して、ローカルラップトップにすばやく切り替えます。 現時点では、スクリプトは正常に機能しますが、ラップトップの電源を切り、最後に家に帰る必要があるため、この方法は少し集合的です。



ラボでテストを実行するには、VNCサーバーを構成する必要があります。セッションから切断しても、アクティブなデスクトップは引き続き無効になります。 これは、私が学び、適用しなければならなかったトリックの1つです。



そしてもちろん、神が奉仕として禁じている同じジェンキンススレーブの下からスクリプトを実行すると、再び何も機能しなくなります。 これはオペレーティングシステムの制限です。 グラフィカルインターフェイスをサービスとして使用することはできません。



他のプラットフォームについて少し。 Linuxには、atspiテクノロジーを使用したpyatspi2というPythonパッケージもあります。 OS Xにはpyatomがあります。 これらは使用するのにあまり便利ではなく、特にコンパイルが必要です。 Pywinautoはコンパイルを必要とせず、単に1行に配置されます。 Javistsは、実際に使用できるJemmyライブラリーを推奨しています。



最近、私たちの小さなコミュニティはこの方向に取り組んでいます。 LinuxおよびOS X上のAtspiテクノロジー。単純なプロトタイプがあり、これは研究の過程にあります。



Javaに関しては、彼らはそこから始めていません。 しかし、多かれ少なかれ使用可能なものから、純粋なCPythonからJavaコードを呼び出すことができるJPypeライブラリがあります。 Java仮想マシンで直接実行されるJythonがあることは知っています。 これはPythonインタープリターでもあり、通常のCPythonとあまり互換性のない機能も備えています。 Javaに向けた開発のより有望な方向として、JPypeが登場します。



もちろん、さらに多くの機能が必要です。 Pywinautoにはすでに他のものがありますが、まだあまり使用されていません。 オペレーティングシステムのイベントをサブスクライブできるときにグローバルフックを実装しました。 , , . , , , .



UI Automation , . , , , . record/replay, , . , , .



— , , . , , , , , , .



. , , EditBoxes - - . , , . , , .



. open source, . .







GUI. ? , , unittest. , - GitHub . Windows Linux. Linux .



, .



, Python. — 95%, .







, , . . , , . UIAutomation . Linux, accessibility API Apple, . , - pywinauto .







— , , . , . Stack Overflow, , . , - . , .



All Articles