新しいコードジェネレーターを使用したスワップ

スワップ SWAPYは、pywinauto(Python)用のグラフィカルUIオートメーションユーティリティです。



バージョン0.4.7では、コードジェネレーターが完全に再設計されています。 主な機能、およびUIの自動テスト用のスクリプトを迅速かつ簡単に作成する方法の例は、catの下を参照してください。



説明



SWAPYは、ウィンドウの階層を表示し、pywinautoライブラリのUIオートメーションコードを生成するためのグラフィカルユーティリティです。



インターフェース



名前自体は、アプリケーションの主要な考え方であるPYthonのSimple Windows Automationを反映した頭字語です。 このユーティリティは、PyInstallerを使用してコンパイルされた完全なexeファイルです。 SWAPYでは、自動化とコード生成のための追加設定は必要ありません。 もちろん、コードをさらに使用するには、少なくともPythonとpywinautoをインストールする必要があります。 しかし、機能をテストするために、そして最も重要なことは、そのような束がアプリケーションの自動化に適しているかどうかを確認するために、SWAPYは完全に自給自足です。



このユーティリティには、次の3つの主要コンポーネントが含まれています。





スクリプトを作成するには、すべてのコントロールのツリーで要素を見つけてから、クリックなどのアクションを呼び出す必要があります。 この場合、アクション自体がオブジェクトに対して実行され、コードのあるフィールドが更新されます。



以前は、コードジェネレーターにはほとんど注意が払われていませんでした。 多くの場合、要素を検索し、そのパラメーターを表示する機能が使用されました。 コードジェネレーターのすべての修正と機能は、残差の原則に従って追加されました。 その結果、機能するコードを取得するために、ユーザー側で一定の努力が必要でした-すべての祖先を順番に初期化する必要がありました。



新しいコードジェネレーターには、以前の欠陥が基本的にありません。



開発履歴



2011年初頭、オートメーションQAエンジニアの立場で、彼はUIオートメーションのライブラリpywinautoを発見しました。 ライブラリ「Old new pywinauto」でライブラリ自体の歴史について学ぶことができます。 当時、実際にはサポートされていませんでした。 ただし、Pywinautoは競合他社をすべて破り、中程度のGUIの複雑さを持つ多数の製品をテストするために選ばれました。



このオプションが選択の主な利点であることに注意してください。



  1. ツール価格。 Pywinautoは無料で、GNU LGPL v.2.1ライセンスの下で配布されます
  2. これはPythonライブラリです。 すべての機能、ライブラリなどを備えています
  3. 環境の簡単な準備。 Python + pywinautoをインストールして仮想マシンをテスト用に準備する方が、たとえばTestCompleteのようなモンスターをインストールするよりもはるかに簡単です。 これは、継続的インテグレーションを使用する場合に非常に重要です。


すぐに、1つの欠点が発見されました。必要な要素を検索し、そのプロパティを分析するのに多くの時間が無駄になりました。 要素のツリーとそのパラメーターを表示するためのグラフィカルユーティリティが本当に不足していました。 グラフィカルインターフェイスを自動化するライブラリは、グラフィカルインターフェイスを備えていると便利です。



この不正を修正することが決定されました。



ロゴヘッド 2011年4月にユーティリティの作業を開始しました。年末までにバージョンは0.3.0に急速に成長し、ユーティリティにはすでにすべての主要コンポーネントと...多くの問題がありました...



翌年にわたって、エラーは徐々に修正され、重要でないものが追加されました。 そして、私は自分自身が使用していないユーティリティをサポートすることに仕事と関心を変えました。



SWAPYは2015年9月にpywinautoのメンバーが自分たちに電話をかけたときに2番目の風を受けました。



それ以来、彼は再びユーティリティを積極的に開発し始めました。 主な改善点は、新しいコードジェネレーターです。



主な機能の1つとしてのコード生成機能に対する姿勢を再考しました。 コードジェネレーターを使用して、開発者にライブラリの追加機能を紹介し、経験豊富な開発者でさえルーチンから救うことができます。



新機能





使用例



次に、テストを自動化するためのスクリプトを作成してみましょう。 私は十分な人生の例を選択し、同時にコードジェネレーターの新しい機能を実証しようとしました。



ライセンステキスト



このテストでは、[About]ダイアログにライセンステキストが表示されることを確認します。 同時に、新しいウィンドウが古いアプリケーションに属し、不要な呼び出しapp = Application().Start(...)



作成しないことをSWAPYが理解していることを確認してください。



ライセンステキストの確認
  1. Notepad ++を手動で起動します。
  2. SWAPY要素のツリーで必要なメニュー項目を見つけてクリックします。

    click_menu
  3. 要素ツリーを更新して新しく開いたウィンドウを表示するには、ツリー内のroot



    要素に選択を置く必要があります。 この場合、すべての子要素が更新されます。
  4. 名前が通常の方法( window.Texts()



    )で決定されていないため、このSWAPY自体がウィンドウのハンドルから名前を形成しました。
  5. ダイアログの階層についてで、ライセンステキストを見つけてクリックします。



    について



    次の行のみが追加されました。



     window = app.Dialog edit = window.Edit2 edit.Click() #    
          
          





    つまり SWAPYは既存のapp



    変数を使用しました。 このテスト用に自動生成されたコードで、完了です。 Notepad ++はテスト後に起動および終了することに注意してくださいapp.Kill_()



    最後の行がこれを担当します。


最終的なテストコードは次のようになります。



 from pywinauto.application import Application expected_text = “...” app = Application().Start(cmd_line=u'"C:\\Program Files (x86)\\Notepad++\\notepad++.exe" ') notepad = app[u'Notepad++'] notepad.Wait('ready') menu_item = notepad.MenuItem(u'&?->\u041e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435...\tF1') menu_item.Click() window = app.Dialog edit = window.Edit2 actual_text = edit.Texts() app.Kill_() assertEqual(expected_text, actual_text)
      
      





ご覧のとおり、最小限のネイティブコード。



タブ順



移動するタブを確認しましょう。 コードを生成する際に故意にミスを犯し、SWAPYがそれを削除する方法を確認します。



タブ順序の変更を確認する
  1. Notepad ++を手動で起動します。
  2. 追加の2つのタブを開きます。 要素ツリーで必要なToolBar



    を見つけ、インデックス0のボタンに対してClick



    アクションを実行します。その結果、コードが表示され、1つの新しいタブが開きます。



    add_tab



    別のタブが必要です。もう一度アクションを繰り返してください。 ボタンテキストは使用できないため、インデックスによるアドレス指定が使用されます。 気づかずに、インデックス1のボタンを誤ってクリックしました。



    追加されたコード:



    fix_code
     toolbar_button2 = toolbarwindow.Button(1) toolbar_button2.Click()
          
          





    修正する必要があります。 繰り返しを繰り返さないために、SWAPYでは最後のコマンドを元に戻すことができます(少なくともすべてのコードを連続して元に戻すことができます)。



    Clear last command



    Clear last command



    すると、最後のコマンド(強調表示されたフラグメント)が元に戻ります-必要なだけです。 コードを完全にクリアするには、 Clear the code



    コマンドがあります。 職場での事故を防ぐため、完全なクリーニングは確認ダイアログの後ろに隠れています。



    ここですべてを正しく行い、インデックス0のボタンをクリックします。



    コードが追加されます:



     toolbar_button.Click()
          
          





    SWAPYは、すでにtoolbar_button = toolbarwindow.Button(0)



    あり、2回目のクリックで初期化する必要がないことを覚えています。

  3. ドラッグアンドドロップでは、 toolbarwindow.DragMouseInput



    メソッドを使用します。 使用法の詳細は、 ドキュメントに記載されています



    タブ座標はsystabcontrol.GetTabRect(0).mid_point()



    を使用して決定できます


テストは次のようになります。



 # automatically generated by SWAPY from pywinauto.application import Application app = Application().Start(cmd_line=u'"C:\\Program Files (x86)\\' u'Notepad++\\notepad++.exe" ') notepad = app[u'Notepad++'] notepad.Wait('ready') systabcontrol = notepad.Tab assertEqual([u'Tab', u'new 1'], systabcontrol.Texts()) toolbarwindow = notepad[u'3'] toolbar_button = toolbarwindow.Button(0) toolbar_button.Click() toolbar_button.Click() assertEqual([u'Tab', u'new 1', u'new 2', u'new 3'], systabcontrol.Texts()) systabcontrol.DragMouseInput( press_coords=systabcontrol.GetTabRect(0).mid_point(), release_coords=systabcontrol.GetTabRect(2).mid_point()) assertEqual([u'Tab', u'new 2', u'new 3', u'new 1'], systabcontrol.Texts()) app.Kill_()
      
      





ここでは、少しのドキュメントを読んで、生成されたコードを少し操作する必要がありました。



テキストを挿入して保存する



テストでは、テキストをコピーして貼り付けてから保存する必要があります。 タスクを複雑にしましょう-Notepad ++は既に実行され、最小化(最小化)されており、標準のメモ帳(コピーの実行元)はまだ起動されていません。



複数のウィンドウで作業する
  1. テストアプリケーションを準備します。 Notepad ++を実行して折りたたみ、テストファイル= "notepad check.txt"で通常のメモ帳を実行します。
  2. オブジェクトのツリーでノートブックを見つけ、エディターのコンテンツをクリックします。



    メモ帳



    メモ帳は元の引数で起動されることに注意してください。
  3. これで、メモ帳++とそのテキストボックスが見つかりました。 最初に展開することを忘れないでください(復元)。



    復元する



    編集者



    すべてが計画通りに進みますが、突然、タスクの条件に従って、Notepad ++が既に実行されていて、コードがそれを実行しようとすることを思い出しました。

    SWAPYはデフォルトでapp = Application().Start ... app.Kill_()



    束を生成します。 ただし、この場合、Notepad ++を再度実行する必要はありません。



    新しいコードジェネレーターを使用すると、「アプローチ」を変更してコードを生成できます。これは事後的に行うこともできます。
  4. Application().Start



    を変更するには、 Application().Start



    Application().Connect



    ますApplication().Connect



    するには、メモ帳++アプリケーションウィンドウのコンテキストメニューを呼び出し、 Application().Connect



    を選択する必要がありApplication().Connect







    つなぐ
  5. テキストをコピーして貼り付けます。後で発行しますが、ここでテキストを保存する必要があるとします。



    save_as
  6. [名前を付けて保存]ウィンドウが開きました。表示するには、要素ツリーを更新する必要があります。 これを行うには、ツリーのルート要素を選択します。 ツリーを更新した後、保存するファイルの名前のフィールドをクリックして(後で変更するため)、保存するボタンをクリックします。



    受け入れる


すべての主要なアクションがありますが、現在はCTRL + C、CTRL + Vコマンドの送信、および実際のテストを取得するためのチェックを追加します。

コマンドを送信するには、組み込みのTypeKeysメソッドを使用します。



以下に全文を示します。



 # automatically generated by SWAPY from pywinauto.application import Application import time import os SAVE_PATH = r"Notepad_default_path" app = Application().Start(cmd_line=u'"C:\\Windows\\system32\\notepad.exe" check.txt') notepad = app.Notepad notepad.Wait('ready') edit = notepad.Edit edit.TypeKeys("^a^c") # Copy all the text app2 = Application().Connect(title=u'new 1 - Notepad++', class_name='Notepad++') notepad2 = app2[u'Notepad++'] notepad2.Restore() scintilla = notepad2[u'1'] scintilla.TypeKeys("^a^v") # Paste the text #Save a file menu_item = notepad2.MenuItem(u'&\u0424\u0430\u0439\u043b->\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u043a...\tCtrl+Alt+S') menu_item.Click() window = app2.Dialog edit2 = window.Edit filename = "checked_at_%s" % time.time() # Compose a filename edit2.TypeKeys(filename) button = window.Button button.Click() with open(os.path.join(SAVE_PATH, filename)) as f: assertEqual(“expected_text”, f.read()) app.Kill_()
      
      







それはさらに良いですか?



もちろん-はい!



説明した例でも、 Click()



を実行Click()



てから、テキストを受信するように手動で変更する必要がありましたTexts()



。 または、手動でTypeKeys



を追加しTypeKeys



。 将来のリリースでは、コンテキストメニューに項目を追加することで、このような人気のあるアクティビティをまだ簡素化していません。



アイテムにアクセスするための形式を制御することはまだできません。 Pywinautoでは、属性window.Edit



を使用して要素にアクセスできます。これが不可能な場合(Python変数の名前が無効)、 __getitem__



window[u'0']



ます。



SWAPYは、アクセスのための最短の名前を見つけ、それを属性として使用しようとします。 動作しない場合は、 __getitem__



ます。 これまでのアイデアは最も簡単です-短いコードを取得します。



しかし、たとえば、「Tab Order」のテストでは、そのような行toolbarwindow = notepad[u'3']



ます。 すべてが機能し、すべてがOKです。 しかし、想像してみてください。しばらくしてこのテストを開いたところ、そのような魔法の数字があります。 トリプルの代わりに、 Toolbar



がありToolbar



-最も理解しやすく、最短の名前ではありません。 計画では、ユーザーに名前(「Name!Name、sister!」)を選択する機会を与えます。



また、オブジェクトのツリーを手動で更新する必要があります。 自動更新は明らかに利便性を追加します。



便利なリンク





PS



新しいコードジェネレーターの機能の議論に積極的に参加してくれた-v-ryabovairelilの仲間に、感謝します。



All Articles