Как в Tele2 автоматизировали тестирование SAP ERP с помощью Python
Привет, Хабр! Меня зовут Анастасия Валеева, я – руководитель группы обеспечения качества в Tele2. Наша команда работает в большинстве своём с SAP ERP, и мы не понаслышке знаем, что автоматизация данной платформы — дело далеко не тривиальное. В этой статье я хочу поделиться с вами, как и зачем мы автоматизировали тестирование с помощью Python.
Зачем мы это придумали
SAP ERP – гибкий инструмент в руках нашей команды. Мы дорабатываем функциональность системы под потребности конкретного бизнес сегмента. Эти изменения производятся по запросу бизнес-пользователей. Объём и влияние доработок могут быть различными, но одно остаётся неизменным – каждая доработка является уникальной. Таким образом, это не простое устранение багов и улучшения текущего функционала, не изменение версионности продукта после оптимизации, а, как правило, абсолютно новый «продукт» в системе. В случае автоматизации функционального тестирования нам потребуется писать автотест на каждую доработку/разработку, что занимает больше времени, чем ручное тестирование (написание автотеста, отладка, оптимизация) + данный автотест с каждой новой разработкой будет уже неактуален, и нужно будет создавать новые и новые из раза в раз. Делаем выводы, что автоматизировать функциональные тексты для нас нерелевантно. А вот регрессионные тесты, которые мы проводим после каждого изменения системы, представляют собой более шаблонные варианты, шаги повторяются, и от их автоматизации есть профит.
Сейчас мы работаем с SAP ERP и интегрированными продуктами (FileNet, BW, Fiori), однако, импортозамещение идёт полным ходом, и мы проводим пилотный проект по миграции на новую платформу. Так или иначе, созданный нами инструмент для автотестов универсален и может быть применён в работе с новой системой.
Как выбирали инструмент автоматизации
Из множества инструментов автоматизации мы выбрали для ознакомления четыре наиболее совместимых с SAP ERP:
SAP Scripting;
Tricentis Tosca;
eCatt;
CBTA.
Анализируя, мы исходили из трёх основных для нас факторов: скорость освоения, простота и гибкость, а также бюджет. По каждому из инструментов мы отметили свои плюсы и минусы, собрали информацию в единую таблицу. И вот что у нас получилось.
По количеству зелёных блоков мы увидели, что нашим критериям в большей степени соответствует SAP Scripting.
Принцип работы данного инструмента состоит в том, что он записывает все действия пользователя в системе, на выходе формирует файл в формате .vbs, который в последующем можно запускать в SAP. Соответственно, при запуске этого файла система будет повторять ваши предварительно записанные шаги. Кроме того, данный файл можно корректировать: удалять лишнее, дописывать недостающее или даже полностью переписать. Для этого необходимо открыть файл либо в блокноте, либо в любом другом редакторе, работающем с кодом.
В процессе пилотирования SAP Scripting помимо технических вопросов мы решали несколько административных задач: удобство использования, гибкость, кастомизация, универсальность, прозрачность.
Мы хотели внедрить такой инструмент, который будет полезен не только группе тестирования, но и другим смежным группам нашего подразделения. И поскольку мы говорим об автоматизации, одним из основополагающих факторов для нас было минимальное участие человека в этом процессе. Согласитесь, часто хочется просто нажать на волшебную кнопку "РАБОТАТЬ", чтобы оно всё само заработало :)
Добиться данного магического эффекта «работает само» нам помог Python. За это отвечала коллега из моей команды — она написала скрипт для робота, который сейчас работает буквально по одному клику.
Что касается прозрачности, то мы пошли по пути, доступному для любого пользователя. Для этого «прикрутили» Python к файлу Excel. Это означает, что сейчас провести регресс может любой сотрудник — достаточно зайти в файл автотеста и нажать кнопку «СТАРТ».
Как это работает
Бизнес-процесс состоит из набора бизнес-операций. Например, создание логистического заказа состоит из заведения заказа, смены статуса подписания договора, деблокирования заказа и создания счёта-фактуры. Для обеспечения полного регрессионного тестирования мы автоматизируем всю цепочку шагов. На выходе получаем Excel-документ со скриншотами и подробной информацией по каждому шагу тестирования. Причём регресс может запустить любой пользователь, не только тестировщик, это доступно в том числе для менеджеров со стороны бизнеса. А полученные данные (скрипты) можно использовать также для генерации тестовых данных.
Существует несколько способов выполнения автотестов.
1. Отдельно по каждому бизнес-процессу.
По каждому модулю финансовой системы SAP ERP создан файл Excel, в котором есть кнопка вызова макроса. По вызову этой кнопки запускается Visual Basic for Applications. VBA обращается к системе SAP и вызывает на выполнение ранее записанный скрипт vbs.Таким образом, мы можем выполнять тестирование по отдельному модулю или бизнес-операции.
2. По всему модулю или нескольким модулям.
Для этих нужд как раз используется Python. Наш робот обращается к SAP, открывая рабочее окно. Далее вызывает необходимые файлы Excel, которые работают по описанному принципу макросов на VBA. Таким образом, мы получаем следующую цепочку:
При этом пользователю необходимо только единожды нажать кнопку ВЫПОЛНИТЬ.
Запуск SAP GUI
#Запуск SAP GUI
import sys
import datetime
import time
import win32com.client
import win32gui
import win32process
import win32api
import win32con
from threading import Thread
class Log:
def __init__(self, text=''):
self.__logs = text
@property
def logs(self):
return self.__logs
@logs.setter
def logs(self, text):
self.__logs = self.__logs + text + '\\n'
class System_check:
def __init__(self, flag=False):
self.__flag = flag
@property
def flag(self):
return self.__flag
@flag.setter
def flag(self, value):
self.__flag = value
def check_EAP():
inplay_children = []
hwnd_EAP = 0
while len(inplay_children) == 0:
wnd = win32gui.FindWindow(None,\"Microsoft Excel\")
def is_win_ok(hwnd, *args):
if wnd != 0 and win32gui.GetParent(hwnd) == wnd:
s = win32gui.GetWindowText(hwnd)
if \"EAP\" in s:
nonlocal hwnd_EAP
hwnd_EAP = win32gui.GetParent(hwnd)
EAP.flag = True
if \"ОК\" in s and win32gui.GetParent(hwnd) == hwnd_EAP:
log = 'система EAP. Выполнение скрипта прервано'
print(log)
inplay_children.append(hwnd)
apply_button = hwnd
win32api.PostMessage(apply_button, win32con.WM_LBUTTONDOWN, 0, 0)
win32api.PostMessage(apply_button, win32con.WM_LBUTTONUP, 0, 0)
win32api.PostMessage(apply_button, win32con.WM_LBUTTONDOWN, 0, 0)
win32api.PostMessage(apply_button, win32con.WM_LBUTTONUP, 0, 0)
text.logs = log + '\\n'
return 0
if wnd != 0:
parent_sap = wnd
win32gui.EnumChildWindows(parent_sap, is_win_ok, None)
time.sleep(1)
def func_logon_sap_launch_script():
inplay_children = []
time.sleep(2)
while len(inplay_children) == 0:
wnd = win32gui.FindWindow(None,\"SAP Logon\")
def is_win_ok(hwnd, *args):
if wnd != 0 and win32gui.GetParent(hwnd) == wnd:
s = win32gui.GetWindowText(hwnd)
if \"OK\" in s:
inplay_children.append(hwnd)
if wnd != 0:
parent_sap = wnd
win32gui.EnumChildWindows(parent_sap, is_win_ok, None)
if len(inplay_children) != 0:
time.sleep(3)
apply_button = inplay_children[0]
win32api.PostMessage(apply_button, win32con.WM_LBUTTONDOWN, 0, 0)
win32api.PostMessage(apply_button, win32con.WM_LBUTTONUP, 0, 0)
time.sleep(1)
def close_security():
i = 0
while i < 10:
wnd1 = win32gui.FindWindow(None,\"SAP GUI Security\")
wnd2 = win32gui.FindWindow(None,\"Безопасность SAP GUI\")
if wnd1:
wnd = wnd1
else:
wnd = wnd2
inplay_children = []
def is_win_ok(hwnd, *args):
if wnd != 0 and win32gui.GetParent(hwnd) == wnd:
s = win32gui.GetWindowText(hwnd)
if \"Allow\" in s:
inplay_children.append(hwnd)
if wnd != 0:
parent_sap = wnd
win32gui.EnumChildWindows(parent_sap, is_win_ok, None)
apply_button = inplay_children[0]
win32api.PostMessage(apply_button, win32con.WM_LBUTTONDOWN, 0, 0)
win32api.PostMessage(apply_button, win32con.WM_LBUTTONUP, 0, 0)
i += 1
time.sleep(5)
Заведение функции для чтения файла Excel
#Заведение функции для чтения файла Excel
===
def function_doc(book, sheets_order_launch, path, Excel):
backslash = book.rfind('\\\\') + 1
path += book[:backslash]
book = book[backslash:]
module = book[:-5]
wb = Excel.Workbooks.Open(path+book)
try:
for sheet in sheets_order_launch:
tl = Thread(target=func_logon_sap_launch_script)
tl.start()
tEAP = Thread(target=check_EAP)
tEAP.start()
if sheet == 'ZFDALLLOAD':
#мониторится появление окна Security и подтверждение загрузки файла
th = Thread(target=close_security)
th.start()
pattern = book + '!' + sheet + '.' + sheet + '_Button_Click'
log = 'запущен ' + book + ' ' + sheet + ' в ' + str(datetime.datetime.now().strftime(\"%d/%m/%Y %H:%M:%S\"))
print(log)
text.logs = log + '\\n'
Excel.Run(pattern)
except Exception as e:
log = f'Возникло исключение: {e} \\nПроблема при выполнении листа {sheet}, файл сохранен'
print(log)
text.logs = log + '\\n'
finally:
now = str(datetime.datetime.today().replace(microsecond=0)).replace(':', '-').replace(' ', '_').replace('.','_')
new_file = ''+ path + 'test'+ module + now + '.xlsm'
print(new_file)
print(f'Файл доступен по адресу {new_file}')
wb.SaveAs(new_file)
wb.Close()
text.logs = f'По книге {book} - сохранен файл {new_file}\\n\\n'
if EAP.flag:
text.logs = 'Открыта система EAP, скрипт завершен'
sys.exit(0)
def function_books():
Подключение к Excel
def function_for_fi():
Excel = win32com.client.Dispatch(\"Excel.Application\")
Excel.Visible = True
try:
path = '\\\\\\SOME_FILE_SERVER\\\\Folders\\\\QA_GROUP\\\\Modules\\\\'
FI_AA = 'FI_AA\\\\FI_AA_ver10.xlsm'
PS = 'PS\\\\PS_ver13_stab.xlsm'
sheets_order_launch_fi = ['AS01','AB01_1','AB01_2', 'AB08_Storno', 'ABUMN_1', 'ABUMN_2', 'ABT1N', 'ZOPROS', 'J3RFDEPRBONUS', 'AFAB', 'ZFIAA_SELL_3', 'ZFIAA_SELL_VGO', 'ZFIAA_DISM_3', 'F92' ]
sheets_order_launch_ps = ['CJ20N','RDB','Orders', 'ZFDALLLOAD', 'ZPS_STATUS', 'ZOPROS', 'ZRASPRED', 'ZPS_STATUS_GEKS', 'ZOPROS_Itog', 'Storno']
На каждом листе в Excel есть подробная входная и выходная информация, при этом входную информацию можно корректировать. Большая часть листов связана между собой, чтобы можно было провести всю цепочку на одних данных, а последующие шаги не зависели от дополнительных действий пользователя.
Все скриншоты, которые создаются в процессе регресса, генерируются вместе с документами и проводками. Лишние скриншоты можно удалить прямо на странице в Excel. При необходимости сотрудник может по номеру документа найти нужную проводку или операцию в SAP. Это является прозрачным и удобным способом анализа логов тестирования.
Рядом с каждым шагом в файле появляется текстовое описание, статус «успешно» или «не успешно» пройден шаг и цветовой индикатор — зеленый означает успешно пройденный этап, красный сигнализирует об ошибках.
Если ошибка является блокирующей для системы и дальнейшее прохождение шагов невозможно, то скрипт остановится, выдаст информационное сообщение и сохранит изменения в файл. Если ошибка не влияет на последующие шаги, то скрипт продолжит работу, а в конце выдаст лог в Excel с отображением корректных и некорректных шагов. При таком раскладе у нас появляется возможность увидеть проблему в моменте и исправить её.
Также, завершение работы скрипта сопровождается звуковым оповещением.
Дополнительно мы настроили автоматическое удаление листов из общей папки через три дня после их создания.
Что в итоге
Мы посчитали, сколько рабочего времени ручных тестировщиков мы экономим при использовании инструмента автоматизации. Получилось, что на один кейс при использовании SAP Scripting мы тратим 31 секунду против 148 секунд при ручном тестировании. Таким образом, 80% времени инженеров высвободилось на другие задачи, и мы смогли повысить эффективность тестирования.
Данный вариант автоматизации является гибким к изменениям. В случае переезда на другую финансовую систему мы перенаправим нашего робота на Python на вызов нужной нам программы. Сейчас одна из наших основных задач – обеспечить качество работы текущего функционала и уже на этой надёжной основе реализовывать улучшения и внедрять новые фичи. Для нашей команды автоматизация тестирования SAP ERP стала интересным и полезным опытом, а бизнесу предоставила доступную, понятную и безотказную систему проверки рабочих процессов.