動的(非線形)GUIテスト

なに


GUI要素でランダムな順序でアクションを実行します。



それは何のためですか?


テストを実行する人は、ホモサピエンスです。 彼にはある知性があります。 この非常に優れたインテリジェンスにより、予期しない状況に関連するアプリケーションの「不条理な振る舞い」を見つけることができなくなります(ごくまれですが、防止されます)。 彼はそのような非論理的な状況を想像することはできません。

ユーザーは量的にQAよりもはるかに優れており、IQにおいても著しく劣っている場合があります。 したがって、予期しないユーザーの行動の可能性は決して極端に小さいわけではありません。

それで、無料のリソースと欲求があると、そのような状況を防ぐための対策を講じることができなくなりますか? -何もない。

次に、ボタンを介した「無意味なクラング」が役立つ特定のタスクを作成します。



まず、この記事で説明するテストオプションは、実際には、既存のGUIテストへの追加としてのみ使用する必要があります。 ボタンの混oticとした「クリック」だけに依存することは、少なくとも愚かです。 正確に何が起こっているのか、何が起こっているのかについての検証はありません。 したがって、最初のオプションは、追加の負の安定性テストと見なすことができます。

2つ目は無限の期間で最も効果的であり、これは多くの場合不可能です。 したがって、測定期間を選択する際には、アプリケーションの複雑さ、そのタイプ、目的から進める必要があります。 たとえば、2つのボタンと1つのチェックボックスで構成される「非サーバー」アプリケーションを24時間駆動することはおそらく意味がありません。



どうやってやるの?


次の説明は、Windowsプラットフォームでアプリケーションをテストするためのものです。

python + pywinautoバンドルを使用することをお勧めします。 pywinautoにはウィンドウ要素へのアクセスに関していくつかの制限がありますが、ほとんどの場合これで十分です。

正直なところ、私は代替案がありません。 私に馴染みのあるすべてのGUIテスト自動化ツールには、以下に示すダイナミズムがありません-テストの時点で既に、コントロールのリストを取得し、それらのタイプを決定し、許容可能なアクションを実行します。

また、Python自体とそのモジュールの機能を過小評価しないでください。 ここでは、ビデオを撮影し、CPUと必要なメッセージを測定できます。その場合、送信します...



何が必要ですか?




SWAPYユーティリティを使用することもお勧めしますこれを使用すると、コントロールのプロパティを見るのに便利で、pywinautoのコードも生成します。 また、pywinautoがアプリケーションのコントロールを認識しているかどうかを確認するためにも使用できます。



試験仕様


  1. アプリケーションウィンドウを起動します。
  2. 利用可能なコントロールをクリックします(ウィンドウを閉じます)。
  3. 失敗基準を確認してください。
  4. 設定した時間の間、手順1〜3を繰り返します。
  5. この時間の終わりに、テストに合格したことを考慮してください。


不合格基準-テストが不合格と見なされる条件。 たとえば、クラッシュレポートウィンドウが実行されている場合、インターネットは応答しません。 また、テストは実行時に失敗したと見なされます(予期しない状況)。



落とし穴




コード


仕様によると:

  1. バイナリを起動し、メインウィンドウが表示されるまで待ちます。

     pywinauto.application.Application().start_(binary_path) pywinauto.timings.WaitUntil(WAIT_TIMEOUT, CHECK_INTERVAL, _check_window)
          
          





  2. enabled_and_visible()



    を使用して、使用可能なコントロールのリストを取得します。 ウィンドウをクリックまたは閉じる要素をランダムに選択します。

     if ready_contr_list and random.randint(0,len(ready_contr_list)): control = random.choice(ready_contr_list) print('Click on - "%s"' % control.Texts()[0].encode('unicode-escape', 'replace')) highlight_control(control) control.Click() else: try: window.Close() except: pass else: print('Close window')
          
          





  3. 失敗基準。 何も思い浮かびませんでした。 スタブを配置します。

     if 1==0: print('') result = TEST_FAILED break
          
          







以下の全文。 さらにいくつかの点に注意したいと思います。

  1. これまでのmake_action



    は、左クリック1回の信号のみをコントロールに送信できます(またはウィンドウを閉じます)。 トピックが興味深い場合、ロジックが複雑になる可能性があります。
  2. highlight_control



    はアクティブなコントロールをhighlight_control



    表示します。 ただ美しい。
  3. スクリプトを実行するには、次を指定する必要があります。

    • 実行可能ファイルへのパス。 パラメーターを使用すると可能です。

      BINARY_PATH = r'"C:\path\app.exe" –params 1 2 3'



    • メインウィンドウのタイトルバーの規則性:

      TITLE_RE = 'My app - .*'



    • メインウィンドウのクラス。 SWAPYを見ます:

      CLASS_NAME = '#32770'







結果


ネイティブのWindows RDPクライアントをテストしました。

わずか1時間で、RDPクライアントのクラッシュをキャッチできました。 成功? -おそらく。 手動で繰り返すことはできませんでした。

それにもかかわらず、誰もまだダンプをキャンセルしていないので、検死が表示されます...



完全なスクリプト:



 import pywinauto import random import thread import time import sys ''' GUI dynamic testing ''' TEST_FAILED = 1 TEST_PASSED = 0 TEST_EXEC_TIME = 60 * 60 WAIT_TIMEOUT = 30 CHECK_INTERVAL = 0.2 BINARY_PATH = r'"C:\WINDOWS\system32\mstsc.exe"' TITLE_RE = 'Remote Desktop Connection' CLASS_NAME = '#32770' def _check_window(): ''' Check window is opened ''' try: pywinauto.findwindows.find_windows(title_re=TITLE_RE, class_name=CLASS_NAME)[0] except: return False else: return True def start_binary(binary_path): ''' Start a binary, wait for window opens ''' if not _check_window(): pywinauto.application.Application().start_(binary_path) pywinauto.timings.WaitUntil(WAIT_TIMEOUT, CHECK_INTERVAL, _check_window) return 0 def get_top_window(title_re, class_name): ''' Return the top window of the binary ''' if not _check_window(): start_binary(BINARY_PATH) app = pywinauto.application.Application() try: app.Connect_(title_re=TITLE_RE, class_name=CLASS_NAME) except pywinauto.findwindows.WindowAmbiguousError: app.Connect_(title_re=TITLE_RE, class_name=CLASS_NAME, active_only=True) return app.top_window_() def enabled_and_visible(all_conrt_list): ''' Return list of ready for action controls ''' ready_contr_list = [] for contr in all_conrt_list: if contr.IsEnabled() and contr.IsVisible(): ready_contr_list.append(contr) return ready_contr_list def highlight_control(control): ''' Highlight control ''' def _highlight_control(control, repeat = 1): while repeat > 0: repeat -= 1 control.DrawOutline(thickness=1) time.sleep(0.7) control.DrawOutline(colour=0xffffff, thickness=1) time.sleep(0.4) thread.start_new_thread(_highlight_control,(control,3)) return 0 def make_action(window): ''' Make action on a control or close a window ''' all_conrt_list = window.Children() ready_contr_list = enabled_and_visible(all_conrt_list) if ready_contr_list and random.randint(0,len(ready_contr_list)): control = random.choice(ready_contr_list) print('Click on - "%s"' % control.Texts()[0].encode('unicode-escape', 'replace')) highlight_control(control) control.Click() else: try: window.Close() except: pass else: print('Close window') def main(): ''' main section ''' start_time = time.time() result = -1 try: #start testig build start_binary(BINARY_PATH) #testing cycle while (time.time() - start_time) < TEST_EXEC_TIME: #get top window window = get_top_window(TITLE_RE, CLASS_NAME) #make an action make_action(window) #check fail criteria if 1==0: print('') result = TEST_FAILED break else: result = TEST_PASSED print('Test passed') except Exception, e: result = TEST_FAILED print('Test failed.\n Exception %s' % e) sys.exit(result) if __name__ == '__main__': main()
      
      






All Articles