python
February 5, 2021

Тестирование с имитацией действий пользователя на Python

Как мы рассмотрели ранее,  проверка работоспособности большой программы должна происходить путем  ее тестирования. Вместе с тем иногда для этого не достаточно выполнить  последовательность команд в одиночном потоке. Например, для имитации  действия пользователя по нажатию кнопки останова или получения внешнего исключения путем разрыва соединения приходится создавать отдельный  поток. То есть, в основном потоке запускается проверяемый метод, а в  другом с некоторой задержкой или при наступлении определенного  события  инициируется  сигнал извне.

Рассмотрим это на примере теста по созданию файла, сохраняющего настройки парсера веб-страниц, о котором я рассказывал ранее.   Сначала разберемся с запуском потоков. Это элемент параллельного  программирования, которое предназначено для одновременной работы сразу  нескольких частей программы.

При  этом в случае с потоками в действительности интерпретатор Python  постоянно переключается между каждым из них, тем самым в любой отдельный  момент времени исполняется только один поток. Истинный параллелизм  достигается при работе с процессами, так как каждый из них может  выполняться на разных процессорах или ядрах процессора и для каждого из  них создается своя копия интерпретатора.

Вместе  с тем наряду с преимуществом параллелизма работа с процессами сложнее в  плане обмена данных или использования общих ресурсов.

Также  отмечу, что высокоуровневые средства параллельного программирования  проще использовать, но они менее гибкие в настройках чем низкоуровневые.  В основном используются при наличии множества одинаковых задач, которые  не требуют сложного обмена данными друг с другом.

Поэтому  остановимся на применении низкоуровневых средств для работы с потоками.  Для запуска потока достаточно импортировать библиотеку  threading, создать экземпляр класса Thread, передать ему функцию для исполнения с аргументами и вызвать метод start.

import threading
thread = threading.Thread(target=имя_функции,\ args=позиционные_параметры,kwargs=именованные_параметры)
thread.start()

Ниже привожу код класса, наследующего unittest.TestCase, с тестовым методом test_start_stop для проверки сохранения файла с именем "params_page_parser" после установки флага останова методом  click_pause (условием является скачивание более трех записей о поединках в рамках турниров UFC методом ufc_fights.start_items_parser, подробнее о программе парсере здесь).

class ScraperTest(unittest.TestCase):

def click_pause(self):

while True:
           time.sleep(0.3)            
           if len(self.ufc_fights.items_list)>3:
               print(len(self.ufc_fights.items_list))
               self.ufc_fights.pause_flag=True
               break

def test_start_stop(self):
       thread = threading.Thread(target=self.click_pause)
       thread.start()
       try:
           self.ufc_fights.start_items_parser()
       except:
           with open('params_page_parser', 'wb') as f:
               tuple_params = self.ufc_fights.save_class_params()
               pickle.dump(tuple_params, f)
               self.assertTrue(os.path.exists('params_page_parser'))

def setUp(self):

tag_container_events='tbody,,'
          tag_event='a,class,b-link b-link_style_black'
          tag_container_el = 'tbody,class,b-fight-details__table-body'
          tag_el = 'a,class,b-flag b-flag_style_green'
          cur_url = self.true_vals_d['cur_url']
          events_url=self.true_vals_d['events_url']
          page_param = 'page'
          delay = 1
          self.ufc_fights = UFCFightsParser(cur_url,events_url,delay,page_param,\
                                         tag_container_events, tag_event,\
                                         tag_container_el,tag_el)