- PVSM.RU - https://www.pvsm.ru -
Выполнение действий над элементами графического интерфейса в случайном порядке.
Человек, выполняющий тестирование, это Homo sapiens, т.е. он обладает неким интеллектом. Этот самый интеллект, мешает (очень редко, но мешает) ему находить «нелепости поведения» приложения связанные с непредвиденными ситуациями. Он просто не может представить себе настолько нелогичную ситуацию.
Пользователь же, намного превосходит QA в количестве и может значительно уступать ему в IQ. Отсюда, вероятность непредвиденного поведения пользователя отнюдь не крайне мала.
Итак, что нам, обладая свободными ресурсами и желанием, мешает принять меры по предотвращению подобных ситуаций? — Ничего.
Теперь сформулируем конкретные задачи, в которых «бессмысленное клацанье» по кнопкам может быть полезно:
Во-первых, вариант тестирования, описанный в данной статье, должен быть использован, действительно, только как дополнение к существующему тестированию графического интерфейса. Полагаться лишь на хаотичное «клацанье» по кнопкам – по меньшей мере, глупо. Нет никакой проверки, что именно происходит да и происходит ли вообще. Поэтому первый вариант можно рассматривать как дополнительное негативное тестирование на стабильность.
Второй же, максимально эффективен на бесконечном отрезке времени, что часто, невозможно. Поэтому, выбирая период измерений, следует исходить из сложности приложения, его типа и назначения. Например, наверно нет смысла 24 часа гонять «несерверное» приложение, состоящее из двух кнопок и одного чекбокса, которое умножает что-то на два, а потом результат делит пополам.
Дальнейшее описание предназначено для тестирования приложений на платформе Windows.
Предлагаю воспользоваться связкой python + pywinauto. Хотя pywinauto [1] и имеет некоторые ограничения в плане доступа к элементам окна, для большинства случаев этого должно быть достаточно.
Честно говоря, альтернативы я не вижу. Все знакомые мне средства автоматизации тестирования GUI не обладают динамичность, показанной ниже – уже во время выполнения теста получать список контролов, определять их тип и выполнять допустимое действие.
Также не стоит недооценивать возможностей самого Питона и его модулей. Тут вам можно и видео снять, CPU замерить и сообщение, куда надо, в случае чего отправить…
Еще рекомендую воспользоваться утилитой SWAPY [3], с помощью нее удобно смотреть свойства контролов, еще она генерирует код для pywinauto. Также с ее помощью можно проверить видит ли pywinauto контролы для вашего приложения или нет.
Fail criteria – условие, при котором тест считать проваленным. Например, запущено ли окно Crash report, не пингуется Интернет, и т.д. Тест также считать проваленным при любом эксепшене (непредвиденной ситуации).
pywinauto.application.WindowSpecification.PrintControlIdentifiers
По спецификации:
pywinauto.application.Application().start_(binary_path) pywinauto.timings.WaitUntil(WAIT_TIMEOUT, CHECK_INTERVAL, _check_window)
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')
if 1==0: print('') result = TEST_FAILED break
Полный текст ниже. Хочется отметить еще несколько моментов:
make_action
пока умеет только посылать сигнал одинарного левого клика на контрол (или закрывать окно). Если тема будет интересна, можно будет усложнить логику.highlight_control
подсвечивает активный контрол. Просто красиво.BINARY_PATH = r'"C:pathapp.exe" –params 1 2 3'
TITLE_RE = 'My app - .*'
CLASS_NAME = '#32770'
Тестировал родной Windows RDP клиент.
Буквально за час удалось поймать краш 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:WINDOWSsystem32mstsc.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()
Автор: moden
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/testirovanie/2590
Ссылки в тексте:
[1] pywinauto: http://sourceforge.net/projects/pywinauto/
[2] http://python.org/getit/: http://python.org/getit/
[3] SWAPY: http://code.google.com/p/swapy/
Нажмите здесь для печати.