Автоматизация тестирования. Начало пути

Добрый день, Хабр!

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

Если вспомнить себя в начале этого пути, то получаются такие исходные данные (готов поспорить, что я не одинок):
  • Есть желание автоматизировать, есть проект, который можно автоматизировать;
  • Больше 50 открытых вкладок в браузере с информацией об автоматизации, selenium’е, построении фреймворков и т.д.;
  • Несколько начатых проектов Visual Studio, которые уже заброшены в результате тупика и осознания неверного подхода;
  • Отсутствие времени, официально выделенного руководством на автоматизацию, т.к. нет опыта, неизвестно что получится (и получится ли).

Руководство – отдельная тема.
Нельзя просто так взять и сказать: «Хочу автоматизировать!» и в итоге получить одобрение и время на выполнение задачи. Руководству нужен результат, поэтому с их стороны очень резонно не выделять время «не известно на что».

Отсюда следуют 2 ситуации:

Ситуация 1.
  • Шаг 1. Тестировшик озвучил идею автоматизации, возможно даже подготовил ТЗ и произвел оценку трудозатрат и окупаемости.
  • Шаг 2. Руководство сказало: «Ок, дружище, приступай. К окончанию срока нужно предоставить отчет о проделанной работе».

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

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

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

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

Размещая эту статью, я преследую несколько целей:
  1. Принести пользу начинающему тестировщику — автоматизатору, помочь быстро создать первый авто-тест и продолжить автоматизировать;
  2. Получить критику по проекту, т.к. он еще допиливается и наполняется;
  3. Найти людей, которые будут использовать систему, получать от них обратную связь о том, какой функционал они бы хотели видеть из того, что нет.

Надеюсь, что статья принесет пользу начинающему автоматизатору.
Также я надеюсь на критику, т.к. приложенный проект в данный момент разрабатывается и нуждается в дополнении.

Что используется:
  • Язык и среда разработки: C# в MS Visual Studio 2012 (проект class library).
  • Управление браузером: Selenium Webdriver.
  • Фреймворк тестирования: NUnit.
  • Для работы с БД (нам ведь нужно откуда-то брать тестовые данные, верно?) на данном этапе используются стандартные OracleClient и SqlClient;

Установка приложений и настройка проекта

Для работы потребуется:

Чтобы закачать проект из репозитория, необходимо в папке (где вы хотите его содержать) открыть git bash и выполнить команду:

git clone git://github.com/4gott3n/AT.git master

Ознакомиться с работой Git можно, например, в этой статье.

Далее открываем файл AT.sln в Visual Studio и видим перед собой Solution, содержащий проект AT (собственно сам фреймворк), а также пример тестового проекта, в котором можно увидеть реализацию страниц, тестов и т.д. (он является удобным примером для создания своего проекта).

Следующий шаг — создание проекта, который будет хранить все ваши тесты, страницы и все остальное.

Что нужно сделать:
  1. Добавить в Solution новый проект (Class library) это название позже нужно прописать в App.config;
  2. Подключить ссылки;
    В итоге должно быть как на картинке:
  3. Создать файл конфигурации App.config;

    В этом файле будут содержаться все основные параметры проекта.
    Подробнее. App.config
    <add key="project_name" value="SampleTestProject"/>  <!-- название вашего проекта -->
     
    <!-- блок настроек для рассылки отчета о запуске тестов -->
        
    <add key="smtp_server" value="адрес smtp сервера" />
    <add key="smtp_port" value="порт" />
    <add key="smtp_login" value="логин" />
    <add key="smtp_password" value="пароль" />
    <add key="mail_from" value="ваш email" />
    <add key="mail_to" value="список рассылки через запятую" />
        
    <!-- end notif config -->  
    <!-- блок настроек браузера -->
        
    <add key="ImplicitlyWait" value="время ожидания элемента (в секундах)" />
    <add key="WaitForAjax" value="время ожидания выполнения ajax (в секундах)" />
    <add key="browser" value="текущий браузер (firefox, chrome или iexplore)" />
    <add key="browser_check_url" value="http://ya.ru" /> <!-- страница для проверка работы браузера -->
        
    <!--  browser config end  -->
    <!-- настройки страниц (webpages) -->
    
    <add key="Yandex" value="http://yandex.ru/" /> <!-- соответствие названия папки внутри WebPages главной странице тестируемой системы (в данном случае внутри папки WebPages должна быть папка Yandex) -->
    
    <add key="dash_prefix" value="___" />
    <!-- обозначение тире в названии namespace  (три нижних слеша)  -->
    
    <add key="extension_prefix" value="__" /> <-- префикс перед расширением файлов страниц (два нижних слеша), к примеру страница index-1.html должна иметь название класса index___1__html -->  
    
    <add key="folder_index_prefix" value="_fld" />
    <!-- открыть папку без имени файла страницы, это если нам нужно открыть папку, не указывая названия файла, например страница https://yandex.ru/test/, в этом случае в папке Yandex должна быть папка test, а в ней класс _fld  -->
    
    <!-- pages config end-->
    <!-- блок настроек базы данных -->
        
    <add key="database_name_prefix" value="db_" /> <!-- префикс строк конфига, содержащих строки инициализации БД-->
    <add key="database_selected_rows_limit" value="50" /> <!-- ограничение на выборку (кол-во строк) -->
        
    <add key="db_test" value="172.18.XX.XX;1521;SID;LOGIN;PASSWORD;oracle" /> <!-- пример строки инициализации БД -->
    
    <!-- формат: host;port;sid;login;password;type  (type может быть либо oracle, либо mssql-->
    
    <!-- data base config end -->
                
    <add key="test_step_prefix" value="step_" /> <!--  префикс в названиях методов для шагов тест-кейса, к примеру step_01   -->
    <add key="test_case_prefix" value="test_" /> <!-- префикс в названиях классов тест-кейсов, к примеру test_000001 -->
        
    <add key="datetime_string_format" value="yyyy-MMM-dd -> hh:mm:ss" /> <!-- формат даты для логирования -->
    <add key="log_file_name" value="system.log" /> <--! название файла для логов -->    
    


  4. Создать папку для страниц (WebPages).

    В этой папке будут находиться файлы с классами страниц.
    Подробнее. WebPages.
    Несколько правил:
    • Папка со страницами должна называться WebPages;
    • Она должна находиться в корне проекта;
    • Внутри нее должны содержаться корневые папки ваших тестируемых системы (к примеру если вы тестируете Яндекс, то в папке WebPages должна быть папка yandex);
    • Страницы в папках должны находиться в тоже же иерархии, как они находятся в тестируемой системе;
      Пример:
      Страница: test.ru/step1/service/index.html
      Иерархия папок: WebPages -> Test -> step1 -> service -> index.html.cs
      Важно: имена папок и классов чувствительны к регистру
    • Названия файлов классов страниц должны соответствовать реальным именам страниц

    Названия классов страниц:
    Пример:
    Страница: index-1.html
    Класс: index___1__html
    Здесь:
    • Дефис в названии страницы заменяется тремя слешами (можно изменить, параметр dash_prefix в App.config);
    • Точка файла заменяется двумя слешами (можно изменить, параметр extension_prefix в App.config;

    Названия классов, когда нет названия файла, а есть только папка:
    Пример:
    Страница: test.ru/step1/service
    Класс: _fld (можно изменить, параметр folder_index_prefix в App.config)

  5. Создать класс Pages.cs

    public static class Pages {  }
    

    Класс будет содержать объекты классов страниц (WebPages);
    Подробнее. Pages.cs
    Этот класс содержит объекты классов страниц, через которые осуществляется доступ к элементам и т.д.

    Несколько правил:
    • В данном классе иерархия подклассов должна совпадать с иерархией в папке WebPages;
    • Класс и все объекты внутри него должны быть public static.

    Пример класса:
    public static class Pages
    {
            public static class Test
            {
                    public static index__html Index = new index__html();
                    public static class step1
                    {
                             public static class service
                             {
                                     public static _fld Main = new _ fld();
                             }
                             public static add__php Add = new add__php();
                     }
              }
        }
    


    При такой записи страницы будут доступны в тестах примерно так:

    Pages.Test.Index.Open();
    Pages.Test.step1.service.Main.Open();
    


  6. Создать папку для тестов (Tests)

    Здесь нет особых правил, достаточно создать в корне проекта папку Tests, внутри нее создать папки с тестами по тестируемым системам так, как душе угодно.
    Подробнее. Tests
    На картинке изображено как это сделано у меня на проекте:


    Очень уместным будет создать два «служебных» теста, которые всегда будут запускаться первым и последним. В первом тесте можно выполнять различные действия по настройке среды, в последнем, к примеру, выполнять очистку стенда и запускать нотификацию.
    Nunit запускает тесты внутри категории в алфавитном порядке (по полному названию классов)

    Для запуска нотификации необходимо выполнить код:
    AT.Service.Notifier.SendNotif();
    

    Также не лишним будет создать класс Environment.cs
    public static class Environment {  }
    

    Лично я использую его для хранения различных глобальных переменных и констант.


Пример создания страницы (WebPages)

Все создаваемые страницы наследуются от базового класса PageBase, который содержит необходимые методы, одинаковые для всех страниц: «открыть», «открыть с параметром», «получить Url».

Пример класса страницы:
public class index__php : PageBase
    {        
        public void OpenVpdnTab()
        {
            new WebElement().ByXPath("//a[contains(@href, '#internet')]").Click();
        }
        public string VpdnAction
        {
            get { return new WebElementSelect().ByXPath("//select[@name='action']").GetSelectedValue(); }
            set { new WebElementSelect().ByXPath("//select[@name='action']").SelectByValue(value); }
        }
        public string VpdnLid
        {
            set { new WebElement().ByXPath("//input[@name='lid']").SendKeys(value); }
        }
        public string VpdnTechlist
        {
            set { new WebElement().ByXPath("//input[@name='file']").SendKeys(value); }
        }
        public string VpdnStartDate
        {
            set { new WebElement().ByXPath("//input[@name='start_date']").SendKeys(value); }
        }
        public void VpdnSubmit()
        {
            new WebElement().ByXPath("//input[@value='Применить']").Click();
        }
}

Правило:
Все элементы, которые присутствуют на странице, должны инициализироваться в момент обращения к ним.

Примеры работы со страницами:
Pages.Test.Index.Open(); — открыть
Pages.Test.Index.Open(“?id=1”); — открыть с параметром
var url = Pages.Test.Index.Url; — получение адреса страницы
Pages.Test.Index.VpdnSubmit(); — запуск функции, прописанной в классе страницы выше

Пример создания тест-кейса (Test)

Как уже отмечалось выше, все тест-кейсы должны лежать в папке Tests.
Все тест-кейсы должны быть public и наследоваться от базового класса TestBase.

Перед названием класса с тест-кейсом должен быть указан атрибут [TestFixture].
Перед каждым шагом тест-кейса должен быть указан атрибут [Test].

Подробнее об атрибутах тестов можно почитать тут.

Пример класса с тест-кейсом:

namespace TestProject.Tests.OSE
{
    [TestFixture]
    [Category("OSE"), Category("OSE_Internet")] /* категории, nunit позволяет запускать тесты выборочно по категориям */
    public class test_253750 : TestBase
    {
        [Test]
        public void step_01()
        {
            Pages.OSE.Inaclogin.Open();
            Pages.OSE.Inaclogin.Login = “user”;
            Pages.OSE.Inaclogin.Password = “password”;
            Pages.OSE.Inaclogin.Submit();

             Assertion("Ошибка авторизации”, () => Assert.AreEqual(Pages.OSE.Inaclogin.IsAuthSuccess, true));
        }
}


Assertion – это проверка выполнения условия.

Формат записи:
Assertion (текст ошибки, () => Assert.любой_accert_из_nunit() );

Почему не используем просто Assert?
Все Assert’ы отлавливаются специальным классом, в котором выполняются действия по регистрации ошибок, логирования и т.д.

Примеры работы с БД

Для работы с БД используется класс AT.DataBase.Executor, содержащий методы:
  • Выполнение запросов на выборку (select);
  • Выполнение запросов типа insert, update, delete (unselect);
  • Выполнение хранимых процедур.

Примеры:

Select:
var query = select col1, col2 from table_name";
var list = Executor.ExecuteSelect(query, Environment.Имя_БД);

Unselect:
var query = “DELETE FROM table_name"; 
Executor.ExecuteUnSelect(query, Environment.Имя_БД);

Выполнение хранимой процедуры:
Executor.ProcedureParamList.Add(new ProcedureParam("varchar", "имя_параметра", «значение»)); /* входной параметр */
Executor.ProcedureParamList.Add(new ProcedureParam("varchar")); /* возвращаемое значение */
var res = Executor.ExecuteProcedure("имя_процедуры", Environment.Имя_БД); 

имя_БД должно соответствовать значению sid из строки инициализации БД в App.config
<add key="db_test" value="172.18.XX.XX;1521;SID;LOGIN;PASSWORD;oracle" /> <! -- пример строки инициализации БД -->


Сбор результатов тестирования и пример отчета:

Как уже упоминалось выше, для запуска нотификации и получения отчета на почту необходимо после запуска последнего теста выполнить код AT.Service.Notifier.SendNotif();
Логика NUnit такова, что он запускает тесты в алфавитном порядке, соответственно чтобы нужный тест запустился последним, его нужно назвать соответствующим образом.

Настройки оповещения указываются в файле App.config.

Пример отчета (он еще сыроват, мало информации):

Autotest Report
000001 Failed step_01: error
След. шаг: Шаг не выполнялся, ошибка на предыдущем шаге
След. шаг: Шаг не выполнялся, ошибка на предыдущем шаге
След. шаг: Шаг не выполнялся, ошибка на предыдущем шаге

Summary:
Pass Rate = 0 %.

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

Подведение итогов.
Стоит отметить, что предлагаемая система еще окончательно не доделана, есть еще много идей, которые будут реализованы (очень надеюсь на предложения по улучшению от дорогого читателя).
Если будет интерес, в следующих статьях я детально опишу работу фреймворка, настройку и запуск тестов.
Насчет запуска тестов скажу лишь, что я в работе использую бесплатный teamcity, он, на мой взгляд, очень удобен и прост в освоении.

Надеюсь, что прочтение этого поста оказалось для кого-нибудь полезным.
Спасибо за внимание.
Share post

Similar posts

Comments 14

    +1
    Просто и доступно. Особенно примечательно, что тестируете не PHP, как в большинстве подобных топиков.

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

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

    Второй путь, как вы правильно заметили, более привлекателен. Но есть одно но: когда я в свободное время изучал тестирование, я тестировал свои личные проекты, а не рабочие. И тут получается либо тратить личное время на рабочие проекты, либо на свои. Я предпочитаю второе.

    За статью спасибо. Очень удачно с темой попали. Я как раз решил плотно заняться c#, а тут про тесты как раз.
      0
      Спасибо за развернутый ответ. Продолжение следует :-)
      0
      Я для тестирования web приложений выбрал BDD подход, легко описывается, отчеты прямо из коробки, большая реюзабельность кода.
      0
      Для небольшого проекта, такой подход вполне приемлем и оправдан. Ежели проект будет расти, то нужно будет думать о поднятии selenium grid, CI, и писать кросбраузерные обертки для действий, и классы для локаторов(на случай, если поменяется id, или вставится лишний div). У так — успехов в этом не легком деле.
        0
        CI используем, насчет grid — пока рановато, но, вероятно, в дальнейшем, буду использовать. Насчет локаторов, на данную секунду достаточно при необходимости менять их в классах страниц. Тесты не работают напрямую с элементами (только через страницы), поэтому небольшие изменения в верстке не очень критичны.
        Насчет «кросбраузерных оберток для действий» не совсем понял, поясните плиз. Сейчас за выбор браузера отвечает параметр в конфиг-файле (или же параметр в teamcity).
          0
          Ну у разных драйверов разные особенности работы. Например ff_последней верссии, как правило поддерживается достаточно минималистично. По этому без опции enableNativeEvents использовать его нет смысла. Actions поддерживаются совершенно по-разному и по этому в том же ff actions.click().build().perform() — в зависимости от версии самого драйвера может как выполниться, так выполниться успешно для некого набора элементов, выкинуть ошибку или просто не нажать на элемент. По этому данное действие в ff принято заменять clickAndHold().release().
          Или например так: у вас по нажатию кнопки вызывается javascript, который добавляет класс элементу. В своём селениум тесте вы нажимаете на кнопку и потом проверяете, что у элемента появился класс. Так довольно часто selenium успевает проверить элемент до того, как js изменит класс. Про ajax я вообще молчу.

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

          p.s.
          А еще есть интернет эксплорер, который желательно тоже тестить :)
        0
        Практика показывает что отчетность осуществляется средствами CI, а не самого фреймворка. Используя, например, Jenkins можно просто опубликовать репорт nunit на странице билда. Скорее всего у тимсити это в коробке есть.
        Для логирования действий можно прикрутить log4net.

        Поиск элементов в веб-страницах удобнее делать с помощью плагина FireBug к браузеру Firefox. Прогодятся также плагины XPath Checker и FireFinder. На мой взгляд это гораздо удобнее чем Selenium IDE.

        Советую посмотреть в сторону паттернов Page Object и Page Factory а также аннотациям FindBy.

          0
          Скорее всего у тимсити это в коробке есть.
          . Да, он генерит отчеты которые можно посмотреть на странице билда, но, насколько я знаю, по-простому не умеет их автоматически отправлять кому надо, для этого и такой костыль:-)

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

          За Checker спасибо, не знал о таком.

          Page Object и Page Factory
          это используется

          Спасибо за фидбек.

        Only users with full accounts can post comments. Log in, please.