Прошу помочь выбрать инструмент для автоматизации тестирования Windows-приложения с GUI на WTL

Здравствуйте!

Мне нужно автоматизировать процесс тестирования продукта написанного на C++ под Windows. Граффический интерфейс, которого создан с помощью WTL(Windows Template Library). Насколько понял WTL это попытка заменить MFC. Автоматизировать буду по принципу “черного ящика” программно “нажимая” на элементы интерфейса: чекбоксы, кнопки,

Я посмотрел в сторону Python-а с его стандартной библиотекой unittest. А также взглянул на pywinauto. Пока склоняюсь к этому решению.

Но хотелось бы услышать мнение более опытных товарищей по части автоматизации тестирования.

1 лайк

Если нужен бесплатный инструмент, они все примерно одинаковые. Это будет библиотека для какого-то языка, без дополнительных удобств. Поэтому разницы нет, если питон как язык ближе - берите питон.
Если есть средства, можно посмотреть TestComplete или Ranorex - с ними будет значительно удобнее разрабатывать и анализировать результаты.

У меня пока нет опыта использования ни TestComplete ни Ranorex. В том и заключается вопрос к опытным товарищам : насколько проще будет автоматизация через TestComplete или Ranorex по сравнению с Python + pywinauto ?

Тестировать десктопное приложение можно по разному. Вы можете тестить UI, тогда можно autoit использовать. Можно тестить функциональность приложения в питоне, тогда придется делать обертку для питона. Если продукт состоит из динамических библиотек, то можно тестить их хоть в С, хоть в питоне подключая их функциональность. Можно делать свои библиотеки с хуками для функций и инжектить их во время выполнения программы в основную. На самом деле - мои ответы пальцем в небо. Нужно хорошо понимать, чего требуется от приложения и тестов, чтобы начать что-то строить. Я сильно сомневаюсь что вам здесь или где либо ещё дадут толковый ответ. Вам нужно беседовать с программистами и совместно решать этот вопрос.
Инструментом будет Win32 API. А тест фреймворк ничего не решает. Они все одинаковые.

Не уверен что подойдет, но вы не смотрели winium?

1 лайк

Самое первое, что вы должны сделать - это пообщаться с разработчиками на предмет того как вы сможете достучаться к контролам WTL-based приложения. Без их помощи в этом вам не поможет ни один бесплатный инструмент. Я не сталкивался TestComplete, но смотрел Ranorex - с его помощью, можно достучаться даже контролов QT-based приложения. По поводу WTL: возьмите свое приложение и пройдитесь по нему spy++ или тем же UI Automation Verify - до многих контролов вы сможете достучаться? Если вы ранее с этим не сталкивались, приведу маленький пример: приложение kPad - WTL-based апликуха - блокнот. Если пройтись по ней спаем, то можно достучаться до следующих контролов:

много вы натестите методом черного ящика приложение, имея доступ к нескольким контролам? В этом случае вам не поможет win32 api, которое , в принцыпе, и используется всякими pywinauto и другими приблудами (отдельный случай Ranorex - там свой spy и инструменты, но и стоит он не дешево)

Если приложение еще в начальной стадии разработки и разработчики смогут сделать для вас изменения, то первое о чем с ними договоритесь - это пусть они задают имя для каждого окна. В этом случае , используя win32, можно дергать конкретный контрол, что не всегда возможно без этого (я имею ввиду без имени окна).
Пример тут же можно посмотреть на скриншоте:

парент “” ToolbarWindow32
чайлды: “” ATL:004166E0 - два
их чайлды: “” Edit

или

парент: “” kSheetsCtrl
чайлды: “” ATL:SCROLLBAR - два

здесь пример простого приложения, так что в иерархии контролов могут быть десятки, например, “” ATL:004166E0 с одим парентом, и используя те же FindWindowEx или EnumChildWindows вы просто получите список хэндлов контролов одинакого класса.

А будет это unittest или nunit, или еще что-то , например, решите использовать java с библиотекой jna, которая позволяет мапить и вызывать Win32 API, с junit (или testng) - это не важно, это всего лишь тестовый фреймоврк.

2 лайка

Отталкивайтесь от того, кто будет писать тесты сейчас и, самое главное, поддерживать все это хозяйство потом. Готовые фреймворки хороши в том числе тем, что там проще кадровый вопрос решать. Ищите спеца со знанием конкретного продукта и передаете ему дело. А если у вас все самописное, да с хуками и аперкотами, то унаследовать это будет гораздо сложнее.

На счет TestComplete и Ranorex. Оба очень хороши. ТС поддерживает больше языков (начиная с 11-й версии есть Python) и в нем лучше (имхо) реализован подход Keyword Tests. У Ranorex только два языка, меньше наворотов, но и ниже цена. Из глобальных отличий - подход к созданию репозитория элементов интерфейса. В ТС это сделано на базе иерархического дерева элементов. В Ranorex на базе xpath.

Настолько же, насколько проще строить дом из готовых блоков или же самому месить глину и обжигать кирпичи :slight_smile: Скорость vs. Свобода творчества

Ок, изначальный вопрос - чем ранорекс и ТС полезны для Win32 приложения, в которое придется скорее всего инжектить свои библиотеки? И чем специалист знающий ранорекс и ТС будет полезнее, чем тот который разбирается в Win API?

Ну, мы 100% не знаем - может придется, а может и нет. А если и придется, то по крайней мере в ТС их можно прописать без проблем. Я про библиотеки с классами интерфейса, если правильно вас понял.

На счет специалиста. Я так вопрос не ставил. Я сказал, что найти спеца, который разбирается в WinAPI и готов вручную писать фреймворк будет очень непросто. И еще сложнее будет передать это дело дальше, другому специалисту, которого в будущем также нужно будет найти и еще уговорить, разобраться в чужом коде и продолжить его развитие.

Вернулся к теме. Смотрю здесь скриншот есть. На скриншоте видно что у всех кнопок есть кэпшины. А значит user32.dll должен справить легко. Пример того как нажать на кнопку Start окна Desktop используя питон:

from ctypes import *

user32 = WinDLL("user32")
EnumWindowsProc = WINFUNCTYPE(c_bool, POINTER(c_int), POINTER(c_int))

def get_button_by_text(parent, title):
    button = []
    def winfun(hwnd, lparam, text=title):
        length = user32.GetWindowTextLengthA(hwnd) + 1
        buf = create_string_buffer(length)
        user32.GetWindowTextA(hwnd, byref(buf), length)
        if text == buf.value:
            button.append(hwnd)
            return(False)
        return(True)

    user32.EnumChildWindows(parent, EnumWindowsProc(winfun), 0)
    for b in button:
        return b

desktop = user32.FindWindowA(None, "Desktop")
start = get_button_by_text(desktop, "Start")
user32.SendMessageA(start, 0x00F5, 0, 0)

Если приложение х64 то придется шаманить больше. Если надо тестировать внутренние функции которые недоступны из UI, то надо юзать kernel32, а программистам эскпортить функции из длл. Либо инжектить код используя CreateRemoteThread, но это темные материи, вам нужно будет хорошо разбираться в ассемблере, да к тому же будут вылеты на ОС разных версий, разрядностей и библиотек разные версий. Проще уже юнит тесты на С++ написать.
Хотя если уж быть честным, то я бы использовал не питон, а AutoIt здесь всё же. Он как-то приспособленнее к подобным задачам blackbox тестирования

Кстати не уверен насчет wtl, но у знакомого на проекте используется GitHub - TestStack/White: DEPRECATED - no longer actively maintained для тестирования WPF приложения.