Карты пользовательского интерфейса

в 13:09, , рубрики: .net, C#, UITesting, Тестирование IT-систем

Большой пласт работы с тестами UI составляют Desktop приложения под Windows. В разных статьях во время написания карт пользовательского интерфейса (PageObject’s) читателю показывают написание локаторов вручную с помощью UISpy.

Пять лет назад количество таких элементов в моих тестах стало слишком велико, контролы стали сложнее, а библиотеки для UI тестирования начали расти как грибы.

Рутину по поиску необходимого XPath было решено преобразовать в радость.

Вначале использовал Visual Studio UIMap Editor: чем сложнее были приложения, тем меньше он меня не устраивал в плане скорости и подстановки локаторов. Причины опишу в отдельной статье по UIAutomation и его обертках (TestStack.White, Cuite, Microsoft UITest и т.д.).

Итак, задача

Сделать простой редактор PageObject’s. Вспомогательные инструменты: UIAVerify.

Общие принципы

  • каждый контрол (Control) рабочего стола обладает поисковыми свойствами и может содержать дочерние элементы
  • контролы группируются в элементы (Element), элементы группируются в пространства имен (Assemblies)
  • Инкапсуляция, наследование, полиморфизм
  • Возможность использовать уже готовые карты. Например, у меня есть уже готовые карты и расширения для DevExpress, AvalonDock, OpenFileDialog и т.д. Я их переношу между проектами

Что получилось

На примере сложения в калькуляторе Windows 10:

  1. Составляю карту для окна «Калькулятор», для этого в редакторе карт из дерева рабочего стола переношу все объекты окна, и убираю лишнее. Можно добавлять элементы и вручную (например, для Selenium), полет фантазии безграничен
  2. Смотрю на сгенерированные названия элементов. Если они мне не нравятся, переименовываю вручную
  3. Сохраняю карту для обертки UIAutomation (Обычный конвертер XML => C#. Обертка может использоваться любая, Selenium, MS UITest, TestStack.White)

Время на все: минуты три

Справа – аналог дерева рабочего стола UIAVerify. Слева: карта

image

Результат

Под версионный контроль отправляется 4 файла:

Карта в XML

<?xml version="1.0" encoding="utf-8"?>
<Map Version="2.0.0.0" Uid="7b797972-8c3c-4dbf-9c30-7cc8ae14afda">
  <Assembly Name="Calc" FrameWork="NavyWindows">
    <Assembly Name="Map" FrameWork="NavyWindows">
      <Element ControlType="Window" Name="Калькулятор" Comment="Window "Калькулятор"">
        <Control Comment="Window "TitleBar"" IsHidden="true" Name="Калькулятор" ControlType="Window">
          <Property Name="Name">Калькулятор</Property> 
          <Control Comment="Button "Close"" Name="ЗакрытьКалькулятор" ControlType="Button">
            <Property Name="AutomationId">Close</Property>
          </Control>
...
</Map>

Сформированная карта для обертки UIAutomation

namespace Calc
{
	public partial class UIКалькуляторWindow : UIWindow
	{
		public UIКалькуляторWindow(UIControl control) { Wrap(control); }
		public UIКалькуляторWindow() {  }
		public static UIКалькуляторWindow Instance 
		{ 
			get { return Desktop.Instance.Get<UIКалькуляторWindow>(XPath); }
		}
        
		public static By XPath { get { return By.Xpath("Name=Калькулятор"); } }
		
		/// <summary>
		/// Button "plusButton"
		/// </summary>
		public UIButton UIПлюсButton
		{
		 	get { return Get<UIButton>(By.Xpath(@"AutomationId=plusButton")); }
		}
...
</Map>

MapExt.cs и всевозможные расширения

namespace Calc
{
	public static class UIКалькуляторWindowExt
	{ 
        public static int Result(this UIКалькуляторWindow  window)
        {
            var textValue = window.UIResultText.Text
                .Replace("На экране показано", "")
                .Replace(" ", "");
            return int.Parse(textValue);
        }
	}
}

Тест CalculationTests.cs

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Calc;
using System.Diagnostics;
using System;

namespace CalcTests
{
    [TestClass]
    public class CalculationTests : IDisposable
    {
        public CalculationTests()
        {
            _process = Process.Start("calc.exe");
            _calc = UIКалькуляторWindow.Instance;
        }

        [TestMethod]
        public void Sum()
        {
            _calc.UIОдинButton.Click();
            _calc.UIПлюсButton.Click();
            _calc.UIПятьButton.Click();
            _calc.UIРавноButton.Click();
            Assert.AreEqual(6, _calc.Result(), "Не совпадает результат");
        }

        public UIКалькуляторWindow _calc { get; set; }
        Process _process;

        public void Dispose()
        {
            _calc.Close();
        }
    }
}

Думаю, альтернативных решений уже много, ссылки и более удачные примеры кидайте в комментариях.

Спасибо за внимание!

Автор: RussianTM

Источник

Поделиться

* - обязательные к заполнению поля