середу, 30 червня 2010 р.

Использование Selenium и MbUnit для автоматизации тестирования веб сайтов (в картинках).

Использование Selenium и MbUnit для автоматизации тестирования веб сайтов (в картинках).
Возможность автоматизированного тестирования под несколькими браузерами.

  1. Подготовка проекта.
  2. Описание роботы c Selenium.
  3. Пример 1.
  4. Пример 2.
  5. Тестирование под несколькими браузерами.

1. Подготовка проекта.
И так приступим. К примеру, у нас есть webaplplication, который нам нужно протестировать, при чём протестировать с клиентской стороны. В этой ситуации конечно ни что не заменит труд тестировщика, но есть несколько уловок, которые позволят уменьшить монотонный труд.
Для этого устанавливаем Gallio и создаем проект в VS с MbUnit тестами.
Теперь попытаемся интегрировать селениум в наш проект.
Устанавливаем Java.
Качаем Selenium RC. Из скачанного нам нужно всего две библиотеки selenium-remote-control-1.0.3.zip\selenium-dotnet-client-driver-1.0.1\ThoughtWorks.Selenium.Core.dll и \selenium-remote-control-1.0.3.zip\selenium-server-1.0.3\ selenium-server.jar
Добавляем в проект эти две библиотеки.
Добавляем для этого проекта референс на ThoughtWorks.Selenium.Core.dll
Потом добавляем следующий класс, который будет подымать селениум сервер:
using System;
using System.Diagnostics;
using MbUnit.Framework;
namespace EHandelSeleniumTest
{
 [TestFixture]
 public class SeleniumTestingSetup : IDisposable
 {
  [SetUp]
  public void Setup()
  {
   seleniumServerProcess = new Process();
   seleniumServerProcess.StartInfo.FileName = "java";
   //относительный путь к библиотеке
   seleniumServerProcess.StartInfo.Arguments ="-jar ../../Tools/Selenium/selenium-server/selenium-server.jar -port " + ServerPort;
  seleniumServerProcess.Start();
  }

  private int _serverPort;
  public int ServerPort
  {
   get
   {
    if (_serverPort<=0)
    {
     return 4444;
    }
    return _serverPort;
   }
   set
   {
    _serverPort = value;
   }
  }
  public bool IsStarted()
  {
   return seleniumServerProcess != null;
  }
  public void Dispose()
  {
   Dispose(true);
   GC.SuppressFinalize(this);
  } 
  protected virtual void Dispose(bool disposing)
  {
   if (false == disposed)
   {
    if (disposing)
     DisposeOfSeleniumServer();
    disposed = true;
   }
  }
  private void DisposeOfSeleniumServer()
  {
   if (seleniumServerProcess != null)
   {
    try
    {
      seleniumServerProcess.Kill();
      bool result = seleniumServerProcess.WaitForExit(10000);
    }
    finally
    {
     seleniumServerProcess.Dispose();
     seleniumServerProcess = null;
    }
   }
  }
  private bool disposed;
  private Process seleniumServerProcess;
 }
}
Теперь добавляем класс, который будет базовым для всех тестов:
using System;
using System.Text;
using System.Threading;
using MbUnit.Framework;
using Selenium;
namespace EHandelSeleniumTest
{
 [TestFixture]
 public class SeleniumBase
 {
  //адрес тестируемого сайта.
  private string sitePath = "http://www.google.com/";
  //тестируемый броузер.
  public string Browser = "firefox";
  protected ISelenium selenium;
  private StringBuilder VerificationErrors;
  SeleniumTestingSetup seleniumServer = new SeleniumTestingSetup();
  [SetUp]
  public void SetupTest()
  {
   seleniumServer.Setup();
   selenium = new DefaultSelenium("localhost", seleniumServer.ServerPort, "*" + Browser, sitePath);
   selenium.Start();
   VerificationErrors = new StringBuilder();
  }

  [TearDown]
  public void TeardownTest()
  {
   try
   {
    selenium.Stop();
   }
   catch (Exception)
   {
    // Ignore errors if unable to close the browser
   }
   Assert.AreEqual("", VerificationErrors.ToString());
   seleniumServer.Dispose();
  }  

 }
 }

2.Описание роботы с Selenium.
Теперь ознакомимся с тулзой для автоматизирование тестирование Selenium Selenium для этого ставим расширение для Firefox
После этого у вас появиться возможность записывать тест сценарии. На сайте проекта есть видео, как начать работать с этой тулзой. В двух словах это выглядит так:
После установки плагина для FF у вас появиться следующий пункт в меню:
Выбираем этот пункт и у нас появиться следующее окно

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

3. Пример 1.
И так, давайте протестируем Google.com и попытаемся найти документацию для Selenium
Открываем Google.com, потом ставим селениум на запись и вводим в поиск «Selenium документация», жмем поиск.


У нас примерно будет следующий результат после всех наших действий.

Теперь нам нужно всё это экспортировать в наши тесты.

Экспортируем тест кейс в C# файл.
У нас получиться примерно такой код:
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using NUnit.Framework;
using Selenium;

namespace SeleniumTests
{
 [TestFixture]
 public class Test
 {
  private ISelenium selenium;
  private StringBuilder verificationErrors;
  
  [SetUp]
  public void SetupTest()
  {
   selenium = new DefaultSelenium("localhost", 4444, "*chrome", "http://change-this-to-the-site-you-are-testing/");
   selenium.Start();
   verificationErrors = new StringBuilder();
  }
  
  [TearDown]
  public void TeardownTest()
  {
   try
   {
    selenium.Stop();
   }
   catch (Exception)
   {
    // Ignore errors if unable to close the browser
   }
   Assert.AreEqual("", verificationErrors.ToString());
  }
  
  [Test]
  public void TheTest2Test()
  {
   selenium.Open("/");
   selenium.Type("q", "Selenium документация");
   selenium.Click("btnG");   
  }
 }
Добавляем этот класс к нашему проекту.

Наследуемся от SeleniumBase класса, после этого удаляем весь мусор, оставив только сам метод с тестом TheTest2Test() переименовываем, и приводим в порядок:
namespace TestProject
{

 [TestFixture]
 public class UnitTest1 : SeleniumBase
 {
  [Test]
  public void TheGoogleTest()
  {
   selenium.Open("/");
   selenium.Type("q", "Selenium документация");
   selenium.Click("btnG");
   selenium.WaitForPageToLoad("1000");
   Assert.IsTrue(selenium.IsTextPresent("Selenium"));
  }
 }
}
В тест мы добавили маленький таймаут, чтоб дать возможность странице загрузиться и проверку на вхождение поискового слова в ответе сайта.

4.Пример 2.
Для второго примера я создал маленькую вебапликацию которая делает сложение двух чисел и выводит результат.

И так запускаем вебапликацию потом включает Selenium на запись.
Теперь продолжаем роботу с аппликацией. Вставляем операнд 1,2 и жмем кнопку.


Экспортируем тест в С# и добавляем проверку результата, не забываем сменить адрес сайта в SeleniumBase.
[Test]
 public void TheSumTest()
 {
  selenium.Open("/Default.aspx");
  selenium.Type("operant1", "3");
  selenium.Type("operant2", "2");
  selenium.Click("button1");
  selenium.WaitForPageToLoad("30000");
  Assert.AreEqual(int.Parse(selenium.GetText("result")),5);
 } 
Спасибо ASP .NET 4.0, а точнее новой фиче как ClientId для контролов. Теперь мы всегда можем знать id элемента и найти его намного проще. Для других версий ASP пришлось бы использовать XPath чтоб найти элемент, так как id элемента динамически перегененрировалось.
И наш пример напоминал бы что такое
[Test]
 public void TheSumTest()
 {
  selenium.Open("/Default.aspx");
  selenium.Type("//input[@id='operant1']", "3");
  selenium.Type("//input[@id='operant2']", "2");
  selenium.Click("//input[@id='button1']");
  selenium.WaitForPageToLoad("30000");
  Assert.AreEqual(int.Parse(selenium.GetText("//span[@id='result']")), 5);
 } 
Мы запросто можем добавить всевозможные проверки или тело теста в цикл.
Представим, что это была не простая задачка на суммирование двух чисел, а более сложные вычисление. Теперь делая изменения в аппликации нам не придётся перепроверять все места, где может возникнуть ошибка, а всего лишь перезапустить тест.

5. Тестирование под несколькими браузерами одновременно.
Если у вас возникло желание протестировать сразу под несколькими браузерами, то нам нужно будет пойти на некоторые ухищрение.
Есть два пути - лёгкий (не совсем корректный) и более тяжёлый:
1. Приводим наш тест метод к следующему виду
[Test] 
[Row("firefox")]
[Row("googlechrome")]  
public void TheGoogleTest(string browser)
{
 Browser = browser;
 selenium.Open("/");
 selenium.Type("q", "Selenium документация");
 selenium.Click("btnG");
 selenium.WaitForPageToLoad("1000");
 Assert.IsTrue(selenium.IsTextPresent("Selenium"));
}
Минус в том, что метод SeleniumBase.SetupTest() вызывается перед TheGoogleTest, поэтому сначала подыматься дефолтно прописанный браузер в нашем случае это FF.
2. Модифицировать SeleniumBase:
Вынести логику с SetupTest в другой метод к примеру
public void RunServer(string browser)
{
 seleniumServer.Setup();
 selenium = new DefaultSelenium("localhost", seleniumServer.ServerPort, "*" + browser,sitePath);
 selenium.Start();
 VerificationErrors = new StringBuilder();
}
[SetUp]
public void SetupTest()
{
}
И с каждого теста вызывать его
[Test] 
[Row("firefox")]
[Row("googlechrome")] 
public void TheGoogleTest(string browser)
{
 RunServer(browser); 
} 
Плюс в том, что теперь будет вызываться конкретно прописанный браузер, а большим минусом есть то что нужно не забывать в каждом тесте прописывать вызов метода RunServer(browser);


Немного сумбурно, но надеюсь, кому-то упростит роботу.
Полезные ссылки:
http://igorbrejc.net/category/development/testing/gallio-and-mbunit
http://lawrencesong.net/2008/01/selenium-element-locators
http://seleniumhq.org/docs/05_selenium_rc.html

1 коментар:

  1. А что SetUpAttribute и RowAttribute не дружат?

    По-моему, хорошо описано: в деталях, с примерами, с картинками - все то, чего ждет запутавшийся девелопер.

    ВідповістиВидалити