Заметки юного автоматизатора... Так уж получилось, что свои тесты я синхронизирую между тремя компами - рабочий ноутбук (ХР), домашний ноутбук (Vista) и домашний комп (Win7). Компьютер у меня очень "вовремя" полетел, так что поставила студию и на домашний ноут. Проблем с двумя ноутбуками не было никаких - все хорошо, все круто, все работает. А потом мне вернули комп... У вас тоже Windows 7? И вы хотите начать автоматизацию? Тогда честно вам скажу, семерка - зло!
Нет. Не так.
Windows 7 - ЗЛО!!! Особенно для начинающих автоматизаторов, которые в код то круглыми глазами смотрят, "ой, а что это?", а тут еще идеально работающий код валится на первой же стадии.
Да да, это страшное слово "Залогиниться". При моих попытках освоить TestComlete я, кстати, семерку так и не победила. Неуверенно тыкаясь в кнопочку рекорда и осторожно корректируя полученный скрипт до понятного, я была страшно огорчена тем, что прекрасно работающие тесты на ХР не запускаются дома. Вообще. Ведь для любого теста надо вначале залогиниться... А он не видит найденный ранее Alias. Пыталась перезаписать скрипт, найти окно логина семерки. Но проиграла этот раунд)))
Потом у меня кончилась триал-версия, так что больше я TestComlete не занималась, и как обойти окно логина там, я не знаю.
Едем дальше. Watin, VS 2010, C#. Все хорошо, все здорово. Запись логина:
browser.DialogWatcher.Add(new LogonDialogHandler(@"login", "password"));
На семерке запускаю - вводит логин и пароль в строку логина, причем упорно так вводит, раз 20 ввел, пока скрипт не остановила. Пошла за помощью к программистам. Посидели, погуглили. Нашли обход.
Делаем так. В панели инструментов у нас есть такая штучка, как Debug, если нет, вытаскиваем ее туда:
Открываем выпадающий список - Configuration Manager. А теперь угадайте, где в этом менеждере кнопка "добавить новую конфигурацию" )))))
Там снова открываем выпадающий список "Active solution configuration " и находим завестную кнопочку "new". Создаем себе "WIN7 Debug"
Потом открываем свойства проекта - закладку Build и вводим в поле Conditional compilation symbols "WIN7"
Сохраняем конфигурацию. Прекрасно, теперь у нас есть 2 одинаковых конфигурации, которые различаются только наличием этих символов.
Переписываем ту строку кода в:
#if
WIN7 Browser.DialogWatcher.Add(new Windows7LogonDialogHandler(@"login", "password"));
#else
Browser.DialogWatcher.Add(new LogonDialogHandler(@"login", "password"));
#endif
Но и это еще не все! Создаем новый класс, пишем туда большой и страшный код, который я приведу внизу, а то не вижу тут тега спойлера. Класс называем "Windows7LogonDialogHandler .cs"
К нему то наша строчка и будет обращаться. Далее все просто. Если запускаем с ХР или Висты - конфигурацию выбираем "Debug", если с семерки - "WIN7 Debug". И все работает!
Ага. Щазззз. Проблемы могут и не кончиться)) Итак, мы прогуглили это дело, нашли тот скрипт для класса "Windows7LogonDialogHandler .cs" , который будет ниже, запустили (у программиста моего тоже семерка на рабочем компе) - работает! Ура?
Прихожу домой, запускаю - открывает окошко логина и... Ничего туда не вводит. Ну хоть не вбивает логин и пароль, как сумашедший, и то хлеб... Но блин, неудобно же! На компе фильмы смотреть, в игры играть и тд и тп, а как поработать надо - ноутбук включать. Одно дело, когда ты там тесты запустил и сидишь себе, играешься на основном компьютере. А когда ты туда лезешь их писать... Согласитесь, неприятно.
Прихожу на работу. Снова копируем мой проект (мои компы его через Dropbox получают, чтобы мне с флешкой каждый день не бегать), ставим у программиста на семерке - работает! Прихожу домой - не работает :(
Подключаю товарищей, дебажим код и что выясняется? У коллеги англ семерка, а у меня - русская. Поменяла в коде три названия, если у вас англ семерка, вам надо будет сменить "Другая учетная запись", "Пользователь" и "Пароль" на англ наименования... А я надеюсь, что мне не придется запускать свои тесты на английской семерке )))))
Хотя надо что-то придумать с этим. Нехорошо. Можно просто еще одну конфигурацию, в принципе, сделать... Надо ли? Ладно, посмотрим. Надеюсь, что когда вы начнете изучать автоматизацию, то проблему логина вы быстро обойдете, уже зная решение :)) А так в принципе это пока единственная проблема семерки, которую я знаю. Дальше все пойдет хорошо, главное, залогиниться!
Собственно, скрипт для русской версии:
using System.Linq;
using System.Windows.Automation;
using WatiN.Core.DialogHandlers;
using WatiN.Core.Native.Windows;
namespace UIModel
{
public class Windows7LogonDialogHandler : BaseDialogHandler{
{
private readonly string _username;
private readonly string _password;
AndCondition _conditions = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window));
readonly AndCondition _listCondition = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ListItem));
readonly AndCondition _editCondition = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));
readonly AndCondition _buttonConditions = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button));
public Windows7LogonDialogHandler(string username, string password)
{
_username = username;
_password = password;
}
public override bool HandleDialog(Window window)
{
if (CanHandleDialog(window))
{
var win = AutomationElement.FromHandle(window.Hwnd);
var lists = win.FindAll(TreeScope.Children, _listCondition);
var buttons = win.FindAll(TreeScope.Children, _buttonConditions);
var another = (from AutomationElement list in lists
where list.Current.ClassName == "UserTile"
where list.Current.Name == "Другая учетная запись"
select list).First(); another.SetFocus();
foreach (var edit in from AutomationElement list in lists
where list.Current.ClassName == "UserTile"
select list.FindAll(TreeScope.Children, _editCondition)
into edits
from AutomationElement edit in edits
select edit)
{
if (edit.Current.Name.Contains("Пользователь"))
{
edit.SetFocus();
var usernamePattern = edit.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
if (usernamePattern != null) usernamePattern.SetValue(_username);
}
if (edit.Current.Name.Contains("Пароль"))
{
edit.SetFocus();
var passwordPattern = edit.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
if (passwordPattern != null) passwordPattern.SetValue(_password);
}
}
foreach (var submitPattern in from AutomationElement button in buttons
where button.Current.AutomationId == "SubmitButton"
select button.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern)
{
submitPattern.Invoke();
break;
}
return true;
}
return false;
}
public override bool CanHandleDialog(Window window)
{
return window.ClassName == "#32770";
}
}
}
Нет. Не так.
Windows 7 - ЗЛО!!! Особенно для начинающих автоматизаторов, которые в код то круглыми глазами смотрят, "ой, а что это?", а тут еще идеально работающий код валится на первой же стадии.
Да да, это страшное слово "Залогиниться". При моих попытках освоить TestComlete я, кстати, семерку так и не победила. Неуверенно тыкаясь в кнопочку рекорда и осторожно корректируя полученный скрипт до понятного, я была страшно огорчена тем, что прекрасно работающие тесты на ХР не запускаются дома. Вообще. Ведь для любого теста надо вначале залогиниться... А он не видит найденный ранее Alias. Пыталась перезаписать скрипт, найти окно логина семерки. Но проиграла этот раунд)))
Потом у меня кончилась триал-версия, так что больше я TestComlete не занималась, и как обойти окно логина там, я не знаю.
Едем дальше. Watin, VS 2010, C#. Все хорошо, все здорово. Запись логина:
browser.DialogWatcher.Add(new LogonDialogHandler(@"login", "password"));
На семерке запускаю - вводит логин и пароль в строку логина, причем упорно так вводит, раз 20 ввел, пока скрипт не остановила. Пошла за помощью к программистам. Посидели, погуглили. Нашли обход.
Делаем так. В панели инструментов у нас есть такая штучка, как Debug, если нет, вытаскиваем ее туда:
Открываем выпадающий список - Configuration Manager. А теперь угадайте, где в этом менеждере кнопка "добавить новую конфигурацию" )))))
Там снова открываем выпадающий список "Active solution configuration " и находим завестную кнопочку "new". Создаем себе "WIN7 Debug"
Потом открываем свойства проекта - закладку Build и вводим в поле Conditional compilation symbols "WIN7"
Сохраняем конфигурацию. Прекрасно, теперь у нас есть 2 одинаковых конфигурации, которые различаются только наличием этих символов.
Переписываем ту строку кода в:
#if
WIN7 Browser.DialogWatcher.Add(new Windows7LogonDialogHandler(@"login", "password"));
#else
Browser.DialogWatcher.Add(new LogonDialogHandler(@"login", "password"));
#endif
Но и это еще не все! Создаем новый класс, пишем туда большой и страшный код, который я приведу внизу, а то не вижу тут тега спойлера. Класс называем "Windows7LogonDialogHandler .cs"
К нему то наша строчка и будет обращаться. Далее все просто. Если запускаем с ХР или Висты - конфигурацию выбираем "Debug", если с семерки - "WIN7 Debug". И все работает!
Ага. Щазззз. Проблемы могут и не кончиться)) Итак, мы прогуглили это дело, нашли тот скрипт для класса "Windows7LogonDialogHandler .cs" , который будет ниже, запустили (у программиста моего тоже семерка на рабочем компе) - работает! Ура?
Прихожу домой, запускаю - открывает окошко логина и... Ничего туда не вводит. Ну хоть не вбивает логин и пароль, как сумашедший, и то хлеб... Но блин, неудобно же! На компе фильмы смотреть, в игры играть и тд и тп, а как поработать надо - ноутбук включать. Одно дело, когда ты там тесты запустил и сидишь себе, играешься на основном компьютере. А когда ты туда лезешь их писать... Согласитесь, неприятно.
Прихожу на работу. Снова копируем мой проект (мои компы его через Dropbox получают, чтобы мне с флешкой каждый день не бегать), ставим у программиста на семерке - работает! Прихожу домой - не работает :(
Подключаю товарищей, дебажим код и что выясняется? У коллеги англ семерка, а у меня - русская. Поменяла в коде три названия, если у вас англ семерка, вам надо будет сменить "Другая учетная запись", "Пользователь" и "Пароль" на англ наименования... А я надеюсь, что мне не придется запускать свои тесты на английской семерке )))))
Хотя надо что-то придумать с этим. Нехорошо. Можно просто еще одну конфигурацию, в принципе, сделать... Надо ли? Ладно, посмотрим. Надеюсь, что когда вы начнете изучать автоматизацию, то проблему логина вы быстро обойдете, уже зная решение :)) А так в принципе это пока единственная проблема семерки, которую я знаю. Дальше все пойдет хорошо, главное, залогиниться!
Собственно, скрипт для русской версии:
using System.Linq;
using System.Windows.Automation;
using WatiN.Core.DialogHandlers;
using WatiN.Core.Native.Windows;
namespace UIModel
{
public class Windows7LogonDialogHandler : BaseDialogHandler{
{
private readonly string _username;
private readonly string _password;
AndCondition _conditions = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window));
readonly AndCondition _listCondition = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ListItem));
readonly AndCondition _editCondition = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit));
readonly AndCondition _buttonConditions = new AndCondition(new PropertyCondition(AutomationElement.IsEnabledProperty, true),new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button));
public Windows7LogonDialogHandler(string username, string password)
{
_username = username;
_password = password;
}
public override bool HandleDialog(Window window)
{
if (CanHandleDialog(window))
{
var win = AutomationElement.FromHandle(window.Hwnd);
var lists = win.FindAll(TreeScope.Children, _listCondition);
var buttons = win.FindAll(TreeScope.Children, _buttonConditions);
var another = (from AutomationElement list in lists
where list.Current.ClassName == "UserTile"
where list.Current.Name == "Другая учетная запись"
select list).First(); another.SetFocus();
foreach (var edit in from AutomationElement list in lists
where list.Current.ClassName == "UserTile"
select list.FindAll(TreeScope.Children, _editCondition)
into edits
from AutomationElement edit in edits
select edit)
{
if (edit.Current.Name.Contains("Пользователь"))
{
edit.SetFocus();
var usernamePattern = edit.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
if (usernamePattern != null) usernamePattern.SetValue(_username);
}
if (edit.Current.Name.Contains("Пароль"))
{
edit.SetFocus();
var passwordPattern = edit.GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
if (passwordPattern != null) passwordPattern.SetValue(_password);
}
}
foreach (var submitPattern in from AutomationElement button in buttons
where button.Current.AutomationId == "SubmitButton"
select button.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern)
{
submitPattern.Invoke();
break;
}
return true;
}
return false;
}
public override bool CanHandleDialog(Window window)
{
return window.ClassName == "#32770";
}
}
}
Мне кажется зря вы тест комплит так рано выбросили) просто немного другой подход нужен судя по тому что я понял из вашего описания о работе с ним.
ОтветитьУдалитьДа, но, согласитесь, 5к за лицензию и 0 - принципиально разные вещи)))
ОтветитьУдалить+ В тесткомплите я мало что понимала - он ищет все сам, делает какие то алиасы, а сама накодить я бы не смогла. И никто не поможет! Программистам он не знаком, так что малейшая помощь растягивается, пока он сам поймет, что тут да как.
А так - в студии, на С#, любого спроси, поможет подскажет, на крайняк продебажим.
Так что для меня тесткомплит вообще не вариант. По цене не вариант, и по поддержке тоже. Всегда лучше выбирать тот инструмент, по которому тебе смогут помочь.
Но, надеюсь, кому-нибудь из будующих автоматизаторов этот текст поможет :)
Я не совсем понял какой логин имеется в виду - логин в винду?
ОтветитьУдалитьИли логин/пароль, который просят когда открываешь в браузере "защищенный" ресурс?
Можете пояснить, пожалуйста ?
Логин/пароль в браузере, конечно, по кнопочке рекорд я не представляю, как можно записать логин в винду :)
ОтветитьУдалитьНу и строчка кода начинается со слова browser...
А зачем автоматизировать логин в винду? о_О
IE 8, Win7 английская, данный код валится на:
ОтветитьУдалить/////////
var another = (from AutomationElement list in lists
where list.Current.ClassName == "UserTile" where list.Current.Name == "Use another account"
select list).First();
/////////
с ошибкой:
"Exception was thrown while DialogWatcher called HandleDialog: System.InvalidOperationException: Sequence contains no elements
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)"
Если же закоментировать Where, то вводит логин, пароль, кликает сабмит, но окошко снова появляется - он снова вводит-кликает и так несколько раз, пока не сваливается. Короче логин не происходит.
Сорри, это код работает (у меня был неправильный пароль), но я нашел более компактное решение, через AutoIt:
ОтветитьУдалитьAutoIt = new AutoItX3();
AutoIt.WinWaitActive("Windows Security", "", 5));
AutoIt.Send(user);
AutoIt.Send("{TAB}");
AutoIt.Send(password);
AutoIt.Send("{TAB}{TAB}{ENTER}");
Нужно только подключить длл-ку:
using AutoItX3Lib;
Сергей, спасибо!
УдалитьОбязательно попробую ваш вариант!)