понедельник, 20 июня 2011 г. - www.msmirnov.ru

Поздравляю Андрея Маркеева!

Хочу поздравить Андрея Маркеева с отличным выступлением на Sharepoint User Group!

Всегда приятно видеть, как человек своими личными усилиями достигает новых планок в своей профессии.
Мой сайт - www.msmirnov.ru

понедельник, 30 мая 2011 г. - www.msmirnov.ru

Создание тестов для Selenium на C# для web-приложений на ASP.NET


Как я и обещал ранее здесь, привожу пример разработки тестовых сценариев для автоматизированного тестирования web-приложений на C# с использованием библиотеки Selenium 2.0b3.

Для первой версии Selenium разработка скриптов на C# также возможна, но она довольно сильно отличается и обладает гораздо меньшими возможностями, так что я бы не рекомендовал ее использовать. При этом, такой продукт, как Selenium IDE, позволяет осуществлять генерацию C# кода только для первой версии Selenium, поэтому для нас он также получается не актуален.

Далее по шагам рассмотрим пример создания тестового сценария проверки логина на тестируемый сайт.
  1. В Visual Studio.NET cоздаем новый проект – библиотеку классов на C#.
    В данную библиотеку помещаем ссылки на библиотеки Selenium:
    • Selenium.WebDriverBackedSelenium
    • WebDriver.Common
    • WebDriver.Remote
    • WebDriver.Remote.Common
    • WebDriver.Firefox
    • WebDriver.IE

    Все эти библиотеки доступны для загрузки с сайта http://seleniumhq.org/download – Скачать необходимо Selenium WebDriver версии 2.0b3 – речь в статье пойдет о ней.

  2. Создаем класс TestFramework который будет предоставлять нам основные функции по выполнению скриптов.

       1:  public class TestFramework
       2:      {
       3:          static RemoteWebDriver _WebDriver;
       4:   
       5:          public static RemoteWebDriver WebDriver
       6:          {
       7:              get
       8:              {
       9:                  if (_WebDriver == null)
      10:                      _WebDriver = new FirefoxDriver();
      11:   
      12:                  return _WebDriver;
      13:              }
      14:          }
      15:   
      16:          public static void OpenURL (string URL)
      17:          {
      18:              WebDriver.Navigate().GoToUrl(URL);
      19:          }
      20:   
      21:          public static IWebElement FindWebElement(WebItem webItem)
      22:          {
      23:              if (webItem.ID != "")
      24:                  return WebDriver.FindElementById(webItem.ID);
      25:   
      26:              if (webItem.ClassName != "")
      27:                  return WebDriver.FindElementByClassName(webItem.ID);
      28:   
      29:              if (webItem.XPathQuery != "")
      30:                  return WebDriver.FindElementByXPath(webItem.ID);
      31:   
      32:              return null;
      33:          }
      34:   
      35:          public static void Delay(int Seconds = 10)
      36:          {
      37:              System.Threading.Thread.Sleep(Seconds * 1000);
      38:          }
      39:      }


    Основу для выполнения тестов представляет собой экземпляр класса RemoteWebDriver, который предоставляет доступ ко все основным функциям Selenium.  

    При этом, экземпляр класса RemoteWebDriver содержит ссылку на объект драйвера, реализующего работу с конкретным браузером – IE, FireFox, Chrome.

    Таким образом, меняя ссылку на конкретный драйвер мы организуем выполнение скриптов на разных браузерах. В данном примере я использую FireFox.

    Метод OpenURL,как видно из названия предназначен для открытия различного рода ссылок.

    Метод FindWebElement реализует поиск элементов на текущей странице браузера. При этом на вход ему подается экземпляр класса WebItem, который будет описан позднее. Пока лишь отмечу, что этот класс предоставляет возможность работы с элементами на странице.

    Данный метод возвращает экземпляр интерфейса IWebElement, который реализуется всеми страничными элементами Selenium.

    Метод использует возможности поиска объектов на странице по их ID, имени css-класса или запросу XPath. Вообще говоря, Selenium предоставляет больше возможностей поиска, но в данном примере я оставил только эти три, как наиболее часто применяемые.

    Последний метод Delay предназначен для приостановки тестов до момент окончания загрузки страниц.


  3. Создаем класс WebItem, который я упоминал выше.

       1:  public class WebItem
       2:      {
       3:          public string ID;
       4:          public string ClassName;
       5:          public string XPathQuery;
       6:   
       7:          public WebItem(string ID, string ClassName, string XPathQuery)
       8:          {
       9:              this.ID = ID;
      10:              this.ClassName = ClassName;
      11:              this.XPathQuery = XPathQuery;
      12:          }
      13:   
      14:          public void Click()
      15:          {
      16:              TestFramework.FindWebElement(this).Click();
      17:          }
      18:   
      19:          public void SetValue(string Value)
      20:          {
      21:              TestFramework.FindWebElement(this).SendKeys(Value);
      22:          }
      23:      }


    Как видим, это наш собственный класс, который предназначен для работы с элементами на веб-страницах.

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


  4. Создаем класс LoginWebItems, который будет содержать набор элементов для работы с формой логина.

       1:  public static class LoginWebItems
       2:      {
       3:          public static WebItem LoginLink
       4:          {
       5:              get
       6:              {
       7:                  return new WebItem("ctl00_Header1_TopHeader1_ExitLinkButton", "", "");
       8:              }
       9:          }
      10:   
      11:          public static WebItem UserNameTextBox
      12:          {
      13:              get
      14:              {
      15:                  return new WebItem("ctl00_ContentPlaceHolder1_EMailTextBox", "", "");
      16:              }
      17:          }
      18:   
      19:          public static WebItem PasswordTextBox
      20:          {
      21:              get
      22:              {
      23:                  return new WebItem("ctl00_ContentPlaceHolder1_PasswordTextBox", "", "");
      24:              }
      25:          }
      26:   
      27:          public static WebItem LoginButton
      28:          {
      29:              get
      30:              {
      31:                  return new WebItem("ctl00_ContentPlaceHolder1_LoginButton", "", "");
      32:              }
      33:          }
      34:      }


    Как видим, класс содержит ссылки на следующие элементы – ссылку на страницу логина, текстовые поля для имени пользователя и пароля, а также непосредственно кнопку логина.


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

       1:  public class PagesActions
       2:      {
       3:          public static void OpenHomePage()
       4:          {
       5:              TestFramework.OpenURL("http://www.test.com/");
       6:          }
       7:      }



  6. Теперь создадим класс LoginAction, который будет нам реализовывать действия входа на сайт.

    Впоследствии это действие может быть использовано во многих тест-кейсах.

       1:  public class LoginAction
       2:      {
       3:          public static void DoLogin()
       4:          {
       5:              LoginWebItems.LoginLink.Click();
       6:   
       7:              LoginWebItems.UserNameTextBox.SetValue("test login");
       8:              LoginWebItems.PasswordTextBox.SetValue("test password");
       9:   
      10:              LoginWebItems.LoginButton.Click();
      11:   
      12:              TestFramework.Delay();
      13:          }
      14:      }


    Как видим, наше действие описано простым языком, в понятных терминах и не содержит кода, зависимого от библиотеки, реализующей выполнение скриптов, т.е. от Selenium.


  7. Ну и наконец мы создаем класс тест-кейса LoginTestCase, который реализует непосредственно тестирование входа на сайт

       1:  public class LoginTestCase
       2:      {
       3:          public static void DoTestCase()
       4:          {
       5:              PagesActions.OpenHomePage();
       6:   
       7:              LoginAction.DoLogin();
       8:          }
       9:      }


Таким образом, расширяя впоследствии наши классы, мы можем описывать новые элементы страниц и сами страницы.


Кроме того, мы можем создавать тестовые действия, непривязанные к конкретному инструменту запуска тестов и комбинировать из наших действий тестовые сценарии.


Затем, мы можем использовать наши сценарии в рамках или встроенного unit-тестирования или для тестирования посредством собственного приложения.


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


Мы можем также организовать автоматическое создание багов в TFS – о том, как это сделать я писал в посте “Как создать work item в TFS (Team Foundation Server) из письма в Outlook

P.S.
Другие мои посты на тему Selenium:
1. От QTP к Selenium
2. Создание тестов для Selenium на C# для web-приложений на ASP.NET
Мой сайт - www.msmirnov.ru

понедельник, 23 мая 2011 г. - www.msmirnov.ru

От QTP к Selenium

Последние несколько лет мы использовали Mercury Quick Test Pro (QTP) для выполнения скриптов автоматизированного тестирования наших web-приложений.

В настоящий момент мы осуществляем переход к Selenium. Именно Selenium будет использоваться для выполнения скриптов регрессионного контроля.


Для нас Selenium имеет целый ряд преимуществ по сравнению с QTP:

1. Selenium бесплатный. QTP стоит очень дорого.

2. Selenium позволяет разрабатывать скрипты на том же языке программирования, на котором ведется основная разработка – C#, Java и пр. Это избавляет от необходимости изучать еще один язык программирования для разработки тестовых сценариев. Благодаря этому, разработчики могут при случае легко вносить изменения в тестовые сценарии, а тестировщики избавлены от необходимости переучиваться, при переходе в разработчики.

3. Так как разработка тестовых скриптов ведется в той же среде, что и основная разработка, скрипты Selenium могут использовать библиотеки тестируемого приложения в своих тестах – например, библиотеки бизнес-логики и пр.

4. Тестовые скрипты Selenium можно включать в наборы unit-тестов тестируемого приложения.

5. Разрабатывая тестовые скрипты на Selenium можно создавать дополнительную функциональность, которая требуется в данном конкретном случае – свой логгинг, свою отчетность, замеры времени тестирования и т.п.


Есть, конечно, и некоторые сложности во внедрении Selenium (куда же без них?):

1. Очень бедная документация.

2. Более высокие требования к опыту тестировщиков в плане умений программировать.

3. Полное отсутствие инструментария разработки.

4. Отсутствие возможности тестировать Windows-приложения.

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

P.S.
Другие мои посты на тему Selenium:
1. От QTP к Selenium
2. Создание тестов для Selenium на C# для web-приложений на ASP.NET
Мой сайт - www.msmirnov.ru

вторник, 10 мая 2011 г. - www.msmirnov.ru

Заметка о мотивации

Пару лет назад я собирал информацию о теории мотивации в ИТ и не только, а также о практических примерах внедрения различных систем мотивации.

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

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

С той поры мне всегда интересно послушать про практические примеры внедрения различных систем мотивации в реально работающих коллективах. Особенно мне интересно, если эта система базируется на каких-либо числовых KPI.

И сегодня один мой коллега, имени которого я не называю, рассказал мне о той системе мотивации, которая принята в их ИТ-подразделении.


Суть системы такова: зарплата программистов складывается из двух часть: оклад + премия (50% от оклада).

Для каждой задачи ставится срок ее сдачи. Если программист не сдает задачу во время, то от премии всего ИТ-отдела, во главе с начальником, вычитается 1% за каждый день просрочки.

Если после сдачи задачи в ней будут найдены баги, то аналогично: минус 1% за каждый баг со всего ИТ-отдела.

Как говорит коллега, такого, чтобы отдел получил 100% премии, не было еще ни разу.

Интересная система мотивации, не находите?
Мой сайт - www.msmirnov.ru

понедельник, 18 апреля 2011 г. - www.msmirnov.ru

Водопад жив…

Недавно я с удивлением узнал, что не смотря на накопленный за последние десятилетия опыт в разработки программного обеспечения и большое количество написанной литературы, водопад (Waterfall) по-прежнему применяется, и причем даже в интернет-проектах.

Причем водопад именно в своем классическом понимании – с длинным циклом разработки, последовательными переходами между фазами, фиксацией требований, кода и пр.

Мой сайт - www.msmirnov.ru

понедельник, 11 апреля 2011 г. - www.msmirnov.ru

Где разместить тестовое окружение?

Некоторое время назад мы рассматривали вопрос о размещении тестового окружения.

Изначально, тестовое окружение у нас располагалось рядом с рабочим – т.е. удаленно у нашего ISP.

Схематично это выглядело так:
image

Как видно на схеме, разработка происходила локально, затем происходило периодическое обновление тестовой системы, где выполнялись все тесты. И, в конце концов, происходило обновление рабочих систем.

Это дает максимальную приближенность тестовой системы к рабочим условиям: быстрый доступ к сторонним поставщикам данных, схожая конфигурация железа и пр.

Однако, такой подход не был лишен и недостатков: он замедлял процесс тестирования и весь процесс разработки.

Происходило это по нескольким причинам:
1. Тратилось очень длительное на время на сравнение схем всех баз данных – около двух часов.
Происходило это потому, что схемы были довольно большие и баз было несколько. Поэтому, приходилось скачивать локально большое количество DDL-скриптов.
2. Очень медленно работало регрессионное тестирование веб-интерфейса. Из-за низкой скорости доступа через интернет на выполнение всех автоматизированных скриптов, которые выполнят все варианты тестирования требовалось около 2-х суток. Конечно, варианты тестирования можно запускать параллельно, но это не решает проблему кардинально.


Было решено перенести тестовое окружение локально, т.е. получить в итоге следующую схему работы:
image

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

При таком подходе, правда, тоже есть подводные камни: в частности не так явно видны проблемы передачи больших объемов данных через интернет – “тяжелый” HTML или большие данные веб-форм и т.п.
Мой сайт - www.msmirnov.ru

пятница, 11 марта 2011 г. - www.msmirnov.ru

Индийский код

Некоторое время назад мне пришлось столкнуться с достаточно большим объемом кода, написанного индийскими товарищами.

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

Я вовсе не хочу сказать, что весь код, который создают индусы, имеет столь серьезные недостатки, так как другого индийского кода я еще не встречал. Однако, огорчает то, что не смотря на явные проблемы в программировании, авторы такого кода имеют достаточный успех на западе.


А теперь конкретные замечания по коду:
1. Очень большой объем дублирования кода. Видно, что Copy-Paste используется очень активно.
Идентичные куски кода повторяются и не выделяются в отдельные функции.

2. Очень длинные многостраничные методы. Отсутствует разбиение на мелкие методы.

3. Использование условий вместо наследований. Т.е. например, вместо того, чтобы создать несколько наследников базового класса, у которого имеется одноименный метод, реализующий различные виды одного алгоритма, создается один метод, поведение которого меняется множеством последовательных повторяющих условий в его теле.
Из-за этого код становиться трудно-расширяемым.

4. Размытие слоев приложения – например, SQL-код генерируется во всех слоях приложения, вплоть до JavaScript’а, исполняемого в браузере.

5. Активное использование именований переменных, при котором первым символом обозначается тип переменной. Например, int iID или string sName. На мой взгляд очень неудобно.

6. Слабое понятие о нормализации баз данных. Большое количество дублирования данных в БД.

7. Именование всех полей в базах данных в верхнем регистре. Например, AUTHOR_NAME.
Мой сайт - www.msmirnov.ru