В данной статье я постараюсь детально рассказать о работе с Coded UI Test, одним из множества нововведений Visual Studio 2010, а так же упомянуть о проблемах, с которыми я столкнулся.
Не будем зря терять время и сразу приступим к тестированию.
У меня уже есть простое WPF приложение, интерфейс которого и будет подвергнут тестированию. Он представляет из себя форму с кнопкой, двумя TextBox'ами для ввода данных и еще одним — для вывода.
Создадим новый тестовый проект, используя Visual Studio 2010.
Добавим новый Coded UI тест. Сделать это можно либо через Solution Explorer, либо через пункт Test главного меню.
Нам предлагается ввести имя файла и выбрать, в какой тестовый проект его добавить.
После нажатия кнопки ОК, появится следующее окно.
Нам предлагают либо записать последовательность действий с помощью специального инструмента Coded UI Test Builder, либо использовать уже готовую последовательность.
Нас интересует первый вариант. Ок. В правом нижнем углу экрана открылся Coded UI Test Builder.
На нем, кроме закрытия и справки, всего 4 кнопки. О них по порядку.
Начать запись.
Просмотреть записанные шаги.
С помощь этой кнопки мы можем изменить карту пользовательского интерфейса (на карте представлены все элементы управления пользовательского интерфейса, отображаемые в тестируемом приложении). И добавить утверждение (assert).
И, наконец, сгенерировать код.
Пока закроем Test Builder и вернемся обратно в студию.
Автоматически в проект добавляются ссылки на следующие базовые сборки.
А так же пустой файл CodedUITest1.cs. В него мы и будем добавлять тестовые методы. Откроем его и создадим метод StartApp(), в котором будет запускаться наше приложение. Чтобы снова запустить Test Builder, нажмем правую кнопку мыши внутри метода.
Примечание: код будет генерироваться в ту строчку, в которой будет вызвано меню. Однако, если мы запустим Test Builder, кликнув правой кнопкой мыши по имени метода, новый код будет сгенерирован над старым кодом.
Атрибут [TestInitialize] говорит о том, что код, помеченный им, будет вызываться при каждом запуске тестового метода.
Exe-файл моего приложения лежит на рабочем столе. Нажимаем Start Recording и запускаем приложение.
Посмотрим на записанные действия.
Видим, что получили именно то, что хотели и теперь мы можем сгенерировать код (При этом запись автоматически будет прервана).
Введем имя для метода.
Вот что у нас получилось.
Здесь
Прежде чем посмотреть реализацию метода
У нас появились 3 новых файла:
Теперь посмотрим на реализацию записанного нами метода в файле UIMap.Designer.cs
Ничего сложного здесь нет, ApplicationUnderTest стандартный класс, наследуемый от UITestControl. Параметрами метода Launch являются просто строковые переменные, которые генерируются автоматически, в этом легко убедиться.
Но есть нюанс.
Если моё приложение положить в папку и попробовать записать его запуск, то мы получим несколько иной эффект.
Если немного вдуматься, то все встает на свои места. Мое приложение принадлежит открытому окну (папке) и записывается уже не запуск приложения (как такового, хотя он тоже произойдет), а Double Click на элементе, принадлежащем записываемому окну.
Чтобы с этим не заморачиваться, мы можем без проблем описать запуск приложения вручную либо создав соответствующий метод в файле UIMap.cs, либо прямо в тестовом методе в файле CodedUITest1.cs как показано ниже.
Аналогично запишем закрытие приложения и пометим метод атрибутом [TestCleanup], атрибут указывает на то, что данный метод будет запускаться каждый раз по окончании каждого метода в тесте.
Посмотрим на реализацию метода
Взаимодействие происходит с помощью статического метода
Самое время записать взаимодействие с интерфейсом нашего приложения.
Создадим в файле CodedUITest1.cs метод
Действуем по проверенной схеме =)
Нажимаем на кнопку генерации кода и указываем имя, я назову метод
Взглянем на реализацию.
Здесь мы видим еще один стандартный класс для взаимодействия с интерфейсом
Наш тест практически готов. Не хватает лишь какой-нибудь проверки =)
Реализуем её. Добавим проверку для TextBox’а, в котором отображается результат, после нажатия на кнопку. Сделать это достаточно просто.
Снова откроем UI Test Builder из метода
Все, что нам доступно для нажатия на данный момент, это кнопка в левом верхнем углу. Нажав ее мы увидим список элементов управления на нашей карте пользовательского интерфейса. На ней будут только те элементы, которые участвовали при записи действий в метод
Примечание: чтобы иметь возможность просмотреть все свойства, необходимо запустить тестируемое приложение.
Нужного нам элемента управления (TextBox3) на карте, естественно, нет. Чтобы добавить его, нам необходимо, удерживая левую кнопку мыши, перетащить “прицел” на наш TextBox. Элемент будет помечен синей рамкой и добавлен в список элементов, затем нажмем Add control to UI Control Map (Alt + C) для добавления элемента на карту.
Примечание: здесь же мы можем переименовать и удалить выбранный элемент.
Для добавления утверждения выберем интересующее нас свойство и нажнем Add Assertion.
Появится диалог, в котором нам предложат выбрать тип утверждения и ожидаемое значение для сравнения.
Сгенерируем код. Я назову метод
Реализация:
Обычный Assert, первым параметром (ожидаемое значение) которому передается переменная со значением “Visual Studio 2010, Hey!”, а вторым (действительное значение) свойство Text нашего элемента управления.
Примечание: у такого подхода есть большой минус. При автоматической генерации методов, включающих утверждения, у нас нет возможности передавать дополнительные параметры в статические методы (например
Все готово. Можно запускать! (Хотя никто и не запрещал сделать это и раньше).
Результаты не заставят себя долго ждать.
Все бы хорошо, но что, если мы хотим использовать внешний источник данных, которые будут использоваться в нашем тесте? Все очень просто. Для этого выполним следующие шаги.
Откроем Test View и в нем выберем наш тестовый метод.
Нам покажут свойства метода, среди них нас интересует Data Connection String. Кликнем на многоточие справа от свойства. Откроется Wizard, в котором предлагается выбрать тип источника данных.
У меня есть заранее заготовленный XML-файл, поэтому я выберу 3 вариант. И нажму Next >
Содержание моего XML-файла:
Указываем путь до файла и сразу можем увидеть набор данных. И еще раз нажимаем Next >
Выбираем таблицу, Next >
И нам любезно предлагают добавить файл в проект. Соглашаемся.
Наш тестовый метод помечается следующими атрибутами:
Теперь данные из моего XML-файла доступны через
Пойдем другим путем.
Воспользуемся еще одним новшеством, функцией Navigate To и поищем сгенерированные Builder'ом методы.
Для передачи параметров в методы, записывающие последовательность действий, генерируется класс
А для передачи параметров в методы утверждений –
Вернемся к нашему тестовому методу
Запускаем тест.
Примечание: если вы достаточно внимательны, то могли заметить, что не смотря на два набора данных для теста, в результате написано, что выполнено 3 из 3:
Связано это с тем, что выполнение теста со всеми наборами данных тоже считается тестом.
Пару раз кликнув на результат тестирования, можно получить более детальный отчет.
Ну вот и все. Тест успешно пройден, но я обещал рассказать о проблемах, с которыми столкнулся.
Вот они:
Изначально предполагалось сделать вывод результата не в TextBox, а в MessageBox.
Но вот что получилось, с разным содержанием MessageBox'а:
Каждый раз создавался новый элемент управления на UI Map. Т.е. если бы я брал данные из того же XML, не добавив элемент с этими данными на карту, то тест бы проваливался. Согласитесь, не очень-то удобно =)
Нельзя записать последовательность действий и добавить assert в один метод с помощью UI Test Builder'a, что тоже не очень-то удобно.
И, наконец, я не смог удалить сгенерированный UI Test Builder'ом метод с записанной последовательностью действий.
UPD: Тестовый проект можно скачать тут.
Не будем зря терять время и сразу приступим к тестированию.
У меня уже есть простое WPF приложение, интерфейс которого и будет подвергнут тестированию. Он представляет из себя форму с кнопкой, двумя TextBox'ами для ввода данных и еще одним — для вывода.
Создадим новый тестовый проект, используя Visual Studio 2010.
Добавим новый Coded UI тест. Сделать это можно либо через Solution Explorer, либо через пункт Test главного меню.
Нам предлагается ввести имя файла и выбрать, в какой тестовый проект его добавить.
После нажатия кнопки ОК, появится следующее окно.
Нам предлагают либо записать последовательность действий с помощью специального инструмента Coded UI Test Builder, либо использовать уже готовую последовательность.
Нас интересует первый вариант. Ок. В правом нижнем углу экрана открылся Coded UI Test Builder.
На нем, кроме закрытия и справки, всего 4 кнопки. О них по порядку.
Начать запись.
Просмотреть записанные шаги.
С помощь этой кнопки мы можем изменить карту пользовательского интерфейса (на карте представлены все элементы управления пользовательского интерфейса, отображаемые в тестируемом приложении). И добавить утверждение (assert).
И, наконец, сгенерировать код.
Пока закроем Test Builder и вернемся обратно в студию.
Автоматически в проект добавляются ссылки на следующие базовые сборки.
А так же пустой файл CodedUITest1.cs. В него мы и будем добавлять тестовые методы. Откроем его и создадим метод StartApp(), в котором будет запускаться наше приложение. Чтобы снова запустить Test Builder, нажмем правую кнопку мыши внутри метода.
Примечание: код будет генерироваться в ту строчку, в которой будет вызвано меню. Однако, если мы запустим Test Builder, кликнув правой кнопкой мыши по имени метода, новый код будет сгенерирован над старым кодом.
Атрибут [TestInitialize] говорит о том, что код, помеченный им, будет вызываться при каждом запуске тестового метода.
Exe-файл моего приложения лежит на рабочем столе. Нажимаем Start Recording и запускаем приложение.
Посмотрим на записанные действия.
Видим, что получили именно то, что хотели и теперь мы можем сгенерировать код (При этом запись автоматически будет прервана).
Введем имя для метода.
Вот что у нас получилось.
Здесь
UIMap
– это свойство, через которые мы будем обращаться к записанным методам, сравнениям и элементам управления пользовательского интерфейса.Прежде чем посмотреть реализацию метода
StartRecordedMethod()
еще раз глянем в Solution Explorer.У нас появились 3 новых файла:
- UIMap.uitest – XML-файл, содержащий все элементы управления на UI Map.
- UIMap.Designer.cs – описание класса UIMap (помечен модификатором
partial
), содержит кодовое представление файла UIMap.uitest. Автоматически генерируемый файл, что очень важно. - UIMap.cs – Файл класса UIMap. Все настройки карты пользовательского интерфейса должны производиться в этом файле.
Теперь посмотрим на реализацию записанного нами метода в файле UIMap.Designer.cs
Ничего сложного здесь нет, ApplicationUnderTest стандартный класс, наследуемый от UITestControl. Параметрами метода Launch являются просто строковые переменные, которые генерируются автоматически, в этом легко убедиться.
Но есть нюанс.
Если моё приложение положить в папку и попробовать записать его запуск, то мы получим несколько иной эффект.
Если немного вдуматься, то все встает на свои места. Мое приложение принадлежит открытому окну (папке) и записывается уже не запуск приложения (как такового, хотя он тоже произойдет), а Double Click на элементе, принадлежащем записываемому окну.
Чтобы с этим не заморачиваться, мы можем без проблем описать запуск приложения вручную либо создав соответствующий метод в файле UIMap.cs, либо прямо в тестовом методе в файле CodedUITest1.cs как показано ниже.
Аналогично запишем закрытие приложения и пометим метод атрибутом [TestCleanup], атрибут указывает на то, что данный метод будет запускаться каждый раз по окончании каждого метода в тесте.
Посмотрим на реализацию метода
CloseAppRecordedMethod()
.Взаимодействие происходит с помощью статического метода
Click
класса Mouse
, в качестве параметров которому передается объект (элемент управления) и координаты щелчка относительно объекта.Самое время записать взаимодействие с интерфейсом нашего приложения.
Создадим в файле CodedUITest1.cs метод
InterfaceTestMethod()
и пометим его атрибутом [TestMethod]
Действуем по проверенной схеме =)
Нажимаем на кнопку генерации кода и указываем имя, я назову метод
InterfaceTestRecordedMethod()
Взглянем на реализацию.
Здесь мы видим еще один стандартный класс для взаимодействия с интерфейсом
Keyboard
. Через статический метод SendKeys
мы сообщаем о нажатии на клавишу табуляции.Наш тест практически готов. Не хватает лишь какой-нибудь проверки =)
Реализуем её. Добавим проверку для TextBox’а, в котором отображается результат, после нажатия на кнопку. Сделать это достаточно просто.
Снова откроем UI Test Builder из метода
InterfaceTestMethod()
и нажмем на третью кнопку слева (добавление утверждения). Скажу пару слов об интерфейсе открывшегося окна.Все, что нам доступно для нажатия на данный момент, это кнопка в левом верхнем углу. Нажав ее мы увидим список элементов управления на нашей карте пользовательского интерфейса. На ней будут только те элементы, которые участвовали при записи действий в метод
InterfaceTestRecordedMethod()
. Выбрав какой-либо элемент в списке, справа мы увидим его свойства. Так же станут активны элементы «Add assertion» и два элемента справа от него (с помощью первого можно обновить список свойств, а с помощью второго – изменять текущий выбранный элемент). Примечание: чтобы иметь возможность просмотреть все свойства, необходимо запустить тестируемое приложение.
Нужного нам элемента управления (TextBox3) на карте, естественно, нет. Чтобы добавить его, нам необходимо, удерживая левую кнопку мыши, перетащить “прицел” на наш TextBox. Элемент будет помечен синей рамкой и добавлен в список элементов, затем нажмем Add control to UI Control Map (Alt + C) для добавления элемента на карту.
Примечание: здесь же мы можем переименовать и удалить выбранный элемент.
Для добавления утверждения выберем интересующее нас свойство и нажнем Add Assertion.
Появится диалог, в котором нам предложат выбрать тип утверждения и ожидаемое значение для сравнения.
Сгенерируем код. Я назову метод
ResultAssertEqualMethod()
.Реализация:
Обычный Assert, первым параметром (ожидаемое значение) которому передается переменная со значением “Visual Studio 2010, Hey!”, а вторым (действительное значение) свойство Text нашего элемента управления.
Примечание: у такого подхода есть большой минус. При автоматической генерации методов, включающих утверждения, у нас нет возможности передавать дополнительные параметры в статические методы (например
AreEqual()
). Но мы можем сделать все самостоятельно в файле UIMap.cs или же в CodedUITest1.cs.Все готово. Можно запускать! (Хотя никто и не запрещал сделать это и раньше).
Результаты не заставят себя долго ждать.
Все бы хорошо, но что, если мы хотим использовать внешний источник данных, которые будут использоваться в нашем тесте? Все очень просто. Для этого выполним следующие шаги.
Откроем Test View и в нем выберем наш тестовый метод.
Нам покажут свойства метода, среди них нас интересует Data Connection String. Кликнем на многоточие справа от свойства. Откроется Wizard, в котором предлагается выбрать тип источника данных.
У меня есть заранее заготовленный XML-файл, поэтому я выберу 3 вариант. И нажму Next >
Содержание моего XML-файла:
Указываем путь до файла и сразу можем увидеть набор данных. И еще раз нажимаем Next >
Выбираем таблицу, Next >
И нам любезно предлагают добавить файл в проект. Соглашаемся.
Наш тестовый метод помечается следующими атрибутами:
Теперь данные из моего XML-файла доступны через
TextContext
. Но нам еще нужно их каким-то образом передать в методы InterfaceTestRecordedMethod()
и ResultAssertEqualMethod()
. Реализованы эти методы в файле UIMap.Designer.cs, поэтому изменить их мы не сможем. Точнее, сможем, но ненадолго (до следующей генерации кода).Пойдем другим путем.
Воспользуемся еще одним новшеством, функцией Navigate To и поищем сгенерированные Builder'ом методы.
Для передачи параметров в методы, записывающие последовательность действий, генерируется класс
XXXParams
, где XXX
– название метода.А для передачи параметров в методы утверждений –
XXXEpectedValues.
Вернемся к нашему тестовому методу
InterfaceTestMethod()
и изменим его следующим образом:Запускаем тест.
Примечание: если вы достаточно внимательны, то могли заметить, что не смотря на два набора данных для теста, в результате написано, что выполнено 3 из 3:
Связано это с тем, что выполнение теста со всеми наборами данных тоже считается тестом.
Пару раз кликнув на результат тестирования, можно получить более детальный отчет.
Ну вот и все. Тест успешно пройден, но я обещал рассказать о проблемах, с которыми столкнулся.
Вот они:
Изначально предполагалось сделать вывод результата не в TextBox, а в MessageBox.
Но вот что получилось, с разным содержанием MessageBox'а:
Каждый раз создавался новый элемент управления на UI Map. Т.е. если бы я брал данные из того же XML, не добавив элемент с этими данными на карту, то тест бы проваливался. Согласитесь, не очень-то удобно =)
Нельзя записать последовательность действий и добавить assert в один метод с помощью UI Test Builder'a, что тоже не очень-то удобно.
И, наконец, я не смог удалить сгенерированный UI Test Builder'ом метод с записанной последовательностью действий.
UPD: Тестовый проект можно скачать тут.