пятница, декабря 30, 2011

Ретроспектива уходящего 2011-го года

Приближается Новый 2012 Год. Для многих людей, эти последние дни 2011 стают временем подведения итогов уходящего года и составлению планов на грядущий 2012-й год.

С профессиональной точки зрения, никому (пока что) незаметным, но очень важным событием для меня стало открытие этого блога “DZis is a Test”. Я работаю в автоматизации тестирования более 6-ти лет, и не знаю почему, но только сейчас решил открыть свой блог по тестированию.  Все это время я вел блоги и по Perl: bless $this, Blog и по C#: .NET ate my MOSK; и писал на Хабр, но, статей по моему основному роду деятельности, по тестированию и автоматизации тестирования у меня целая одна. Будем заполнять этот пробел!

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

И с другой стороны Киев – это такое место на глобусе Украины, в котором происходят События.  Самые разные и на любой вкус.
Одним из таких событий в этом году, был трейнинг Натальи Руколь http://quality-lab.ru/ о Планировании и проектировании тестов:

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

И еще один проект и идея: txt.zhariy.com – блог двуязычных (английскийи русский) переводов англоязычных статей и блогов IT тематики.  Реализация очень простая: Блог на Blogger + несколько строк CSS кода + несколько часов свободного времени и… получается проект, которому нет аналогов в русскоязычном сегменте Интернета. Я понимаю, что читая этот текст, вы уже вбиваете в Google фразу Параллельные тексты на английском и русском, и вы найдете в поисковой выдаче достаточно сайтов с книгами или статьями любой тематики, но не IT-шной.

Многие уважаемые айтишные сайты для публикуют «ссылки за неделю».  Но, вот только большинство таких ссылок ведут на англоязычные ресурсы, а большинство русскоязычных программистов реально напрягает огромное количество латинских букв в статьях (если только это не исходный код, исходники – это святое).

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

Кроме того, я планирую идти вперед и сделать двуязычную версию “DZis is a Test”, как эксперимент.  Я не могу похвастаться своим сверх хорошим английским, но я уж точно могу перевести свои мысли на английский лучше, чем Google Translate.
В следующем году я сделаю все для того, чтобы у меня было чем гордиться и похвастаться.  Я уверен в том, что яркие моменты и достижения превращают мое существование на этой планете в жизнь :)

Желаю всем дочитавшим до этой строчки удачно встретить Новый Год. И не просто его пережить, а обязательно исполнить свои самые заветные мечты и достичь намеченных целей.
И будем надеяться на то, что тот чувак из племени Майя просто задолбался составлять календарь, и остановился на дате 23 декабря 2012года, а не то, что нас ожидают Армагеддоны, Апокалипсисы и Концы Света. Хотя, если фильмы с таким названием выйдут – я обязательно посмотрю. И хотелось бы верить в календарь Windows 7, который расписан до 31-го декабря 2099 года.

воскресенье, декабря 25, 2011

Что такое Page Object

Я спросил у Яндекса,
Что такое Обджект Пейджевый
Яндекс не ответил мне, качая головой…
Я спросил у Гугеля…
 





О паттерне автоматизированного тестирования Page Object говорят много, говорят разное, но, к сожалению, в основном только на английском. Но, четкого определения этому паттерну никто пока еще не дал, и всяческие нюансы каждый описывает и реализовывает по-своему.

Page Object – это структурный шаблон проектирования, используемый в автоматизированном тестировании пользовательского интерфейса для разделения высокоуровневой тестовой логики от низкоуровневой логики поиска конкретных элементов пользовательского интерфейса.

В результате применения Page Object, в любом языке программирования, получается отдельный класс, который содержит декларацию всех элементов текущей страницы (это веб страница в случае веб приложений либо диалоговое или главное окно десктопного приложения) либо отдельных элементов страницы, так называемых Page Element или Component.

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


Dante Briones: Beyond Page Objects
Видео и презентация в хорошем качестве. Данте рассказывает про Page Elements и Page Objects



Dante Briones: Page Object Model for Selenium Scripting
Видео (технически) не очень хорошего качества, но тут Данте очень подробно рассказывает о Page Object.

Ссылка на видео.




См. Также: Блог Dante Briones

Релиз Craig's Utility Library 3.0

Craig's Utility Library -- это одна из крупнейших библиотек расширений для C# и всевозможных вспомогательных функций.
Около 300 всевозможных полезностей помогут не только программисту, но и тестировщику-автоматизатору.
Вот всего лишь несколько примеров:

IDictionary extensions
  • Sort
  • SortByValue
IEnumerable extensions
  • Exists
  • For
  • ForEach
string extensions 
  • Encode
  • FromBase64
  • FormatString
  • RegexFormat
Various value type extensions 
  • ToBool (int)
  • ToInt (bool)
Serialization extensions 
  • ToBinary
  • ToJSON
  • ToSOAP
  • ToXML
  • ToObject

Uri extensions
  • Read
  • ReadBinary

Various reflection related extensions
  • CallMethod
  • CreateInstance
  • DumpProperties
  • GetAttribute
  • GetAttributes
Email
  • Pop3 client (SSL capable)
  • MIME parser
  • SMTP email sending (SSL capable)
  • Exchange inbox email retrieval
Image manipulation (one of the larger collections of functions dealing in image manipulation out there)
Cropping, resizing, rotating, flipping
To black and white or sepia tone

WMI query helpers

Randomization
Including string randomization based on allowable characters, date randomization, Color, Enum, TimeSpan, and Lorem Ipsum generation.

И много-много другого. Все вышеперечисленное – это лишь 10-я часть от полного списка возможностей Craig's Utility Library.

пятница, декабря 23, 2011

О вреде неправильных (всех!) примеров кода автоматизации тестирования

Вот вы, значит, сидите себе спокойно, кофе попиваете, на кнопочки кликаете, и тут к вам залетает ваш взмыленный руководить проекта/начальник/тим лид или генеральный директор и говорит:

«Нам нужна автоматизация тестирования, а то без нее никак, все развалится, а будет – дадим тебе синьйора с бонусами!».

Ну, значит, сидите вы после этого замотивированный толи негативно, толи позитивно, в общем – неважно, но важно то, что работу то нужно работать.

Ну, значит, оглянулись вы по сторонам, а вокруг на проекте – Дикий Запад, в кого не плюнь все на C# и .NET пишут. Да, и вы вспомнили, что когда-то толи на C# толи на ASP.NET что-то делали. И совсем недавно какой-то слух прошел, что вышел Selenium Webdriver 2, который, говорят, лучше первой версии и все на нем значит, автоматизацию и готовят.

Тут вы забиваете а Гуугл заклинание: selenium webdriver c# tutorial



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

Вот самая первая ссылка вполне подходит:

http://www.theautomatedtester.co.uk/tutorials/selenium/selenium_two_csharp_nunit.htm

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

Давайте рассмотрим этот пример теста более детально:

using OpenQA.Selenium;
using OpenQA.Selenium.IE;
 
using NUnit.Framework;
 
namespace Selenium.Two.DotNetExample
{
    [TestFixture]
    public class Test_Google
    {
        IWebDriver driver;
         
        [SetUp]
        public void Setup()
        {
            driver = new InternetExplorerDriver();
        }
        
        [TearDown]
        public void Teardown()
        {
            driver.Quit();
        }
            
        [Test]
        public void TestSearchGoogleForTheAutomatedTester()
        {
            //Navigate to the site
            driver.Navigate().GoToUrl("http://www.google.co.uk");
            //Find the Element and create an object so we can use it
            IWebElement queryBox = driver.FindElement(By.Name("q"));
            //Work with the Element that's on the page
            queryBox.SendKeys("The Automated Tester");
            queryBox.SendKeys(Keys.ArrowDown);
            queryBox.Submit();
            //Check that the Title is what we are expecting
            Assert.True(driver.Title.IndexOf("The Automated Tester") > -1);
        }
    }
}

Вот вы все подключили, и NUnit с Webdriver скачали:

И даже тест в NUnit запустили, и он даже прошел, но:


NUnit вам показывает какую-то фигню в ошибке:


Selenium.Two.DotNetExample.Test_Google.TestSearchGoogleForTheAutomatedTester:
Expected: True
But was: False


Значит, вы искали «The Automated Tester», а получили что-то другое? Отлично. А что? А что вы еще хотели от Assert.True, который служит для проверки булевых значений, а не для строк?

//Check that the Title is what we are expecting
Assert.True(driver.Title.IndexOf("The Automated Tester") > -1);

На этом можно было бы не заострять внимание, но если бы вы знали, сколько раз встречаешь в реальном коде именно такое…
Давайте сразу же исправим:

//Check that the Title is what we are expecting
StringAssert.Contains("The Automated Tester", driver.Title);


И получим следующий результат после теста:



Тест продолжает безнадежно валится, но давайте уже его допилим, и без лишних излишеств очень топорно поставим Sleep на 2 секунды. Что, конечно же, является огромной ошибкой, но для примера сойдет. Ведь пример – это игрушечный код.

System.Threading.Thread.Sleep(2000);

//Check that the Title is what we are expecting
StringAssert.Contains("The Automated Tester", driver.Title);


Да, сейчас NUnit выдает более понятную ошибку:
Selenium.Two.DotNetExample.Test_Google.TestSearchGoogleForTheAutomatedTester:
Expected: String containing "The Automated Tester"
But was: "the automated tester - Поиск в Google"


И эта ошибка говорит, что, с учетом регистра символов, строка "The Automated Tester" не была найдена в строке "the automated tester - Поиск в Google".

Можете сами попробовать. Сейчас Google, при поиске, помещает в свой заголовок поисковую фразу в нижнем регистре символов. Я считаю, что это бага, и обязательно напишу репорт в Гуугл.

А вот теперь давайте подумаем над следующим вопросом:
Сколько в этом тесте тестового кода? То есть, кода, который что-то тестирует?
Сходу можно ответить: Да ты что, тут весь код тестовый, это же тест!

Да?! А давайте этот тест немного порефакторим:

using OpenQA.Selenium;
using OpenQA.Selenium.IE;

using NUnit.Framework;

namespace Selenium.Two.DotNetExample
{
    [TestFixture]
    public class Test_Google
    {
        IWebDriver driver;

        [SetUp]
        public void Setup()
        {
            driver = new InternetExplorerDriver();
        }

        [TearDown]
        public void Teardown()
        {
            driver.Quit();
        }

        public class GoogleSearchPage
        {
            IWebDriver drv;

            string DefaultUrl = "http://www.google.co.uk";

            public IWebElement QueryBox { get { return drv.FindElement(By.Name("q"));  } }

            public GoogleSearchPage(IWebDriver drv)
            {
                this.drv = drv;
            }

            public void Show()
            {
                Show(DefaultUrl);
            }

            public void Show(string url)
            {
                //Navigate to the site
                drv.Navigate().GoToUrl("http://www.google.co.uk");
            }

            public void Search(string searchPhrase)
            {
                Show();
                //Work with the Element that's on the page
                QueryBox.SendKeys("The Automated Tester");
                QueryBox.SendKeys(Keys.Enter);
                System.Threading.Thread.Sleep(2000);
            }
        }

        [Test]
        public void TestSearchGoogleForTheAutomatedTester()
        {
            string googleSearchPhrase = "The Automated Tester";
            var googlePage = new GoogleSearchPage();

            googlePage.Search(googleSearchPhrase);
            StringAssert.Contains(googleSearchPhrase, driver.Title);
        }
    }
}

Что случилось?
Появился класс, который скрыл в себе все технические детали теста. Теперь этот класс можно использовать повторно и вынести в отдельный файл, чтобы глаза не мозолил.
Теперь на тест не содержит деталей даже о том, что мы используем Selenium. Там две строчки кода, которые просто объявляют переменные, одна строчка действия и одна проверка.

Ну, хорошо, а что если нам нужно написать второй тест кейс?
Тогда наш код будет выглядеть так:

[Test]
        public void TestSearchGoogleForTheAutomatedTester()
        {
            string googleSearchPhrase = "The Automated Tester";
            var googlePage = new GoogleSearchPage(driver);

            googlePage.Search(googleSearchPhrase);
            StringAssert.Contains(googleSearchPhrase, driver.Title);
        }

        [Test]
        public void TestSearchGoogleForTheDZisIsATest()
        {
            string googleSearchPhrase = "DZis is a test";
            var googlePage = new GoogleSearchPage(driver);

            googlePage.Search(googleSearchPhrase);
            StringAssert.Contains(googleSearchPhrase.ToLower(), driver.Title.ToLower());
        }

Вместо вот этого:

[Test]
        public void TestSearchGoogleForTheAutomatedTester()
        {
            //Navigate to the site
            driver.Navigate().GoToUrl("http://www.google.co.uk");
            //Find the Element and create an object so we can use it
            IWebElement queryBox = driver.FindElement(By.Name("q"));
            //Work with the Element that's on the page
            queryBox.SendKeys("The Automated Tester");
            queryBox.SendKeys(Keys.ArrowDown);
            queryBox.Submit();
            //Check that the Title is what we are expecting
            Assert.True(driver.Title.IndexOf("The Automated Tester") > -1);
        }

        [Test]
        public void TestSearchGoogleForTheDZisIsATest()
        {
            //Navigate to the site
            driver.Navigate().GoToUrl("http://www.google.co.uk");
            //Find the Element and create an object so we can use it
            IWebElement queryBox = driver.FindElement(By.Name("q"));
            //Work with the Element that's on the page
            queryBox.SendKeys("DZis is a test");
            queryBox.SendKeys(Keys.ArrowDown);
            queryBox.Submit();
            //Check that the Title is what we are expecting
            Assert.True(driver.Title.IndexOf("DZis is a test") > -1);
        }



Было бы глупо, если бы я был против простых примеров кода автоматизированного тестирования.

Но, я хочу подчеркнуть то, что код в примерах сознательно упрощен. Единственна я цель примера кода c использованием Selenium – это показать то, как вы можете кликать на кнопочки и вводить текст. Но не, рассказать о том, как вам нужно правильно писать тесты.

Это приемлемо, когда у вас в одном тесте используются, и детали о том как Селениум должен найти кнопку, и сколько времени подождать и какой идентификатор у чекбокса…

Но, когда у вас таких тестов 300? Что будет, если идентификатор одного элемента изменится, и чтобы все исправить вам будет необходимо перелопать 300 тестов? И это вместо того чтобы вынести все в отдельное место, в отдельный класс. Ведь тогда вам будет необходимо изменить этот идентификатор лишь в одном месте.

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