Тестирование с имитацией действий пользователя на 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)