понедельник, 26 мая 2008 г.

GUI-тесты на Selenium

Задача следующая: надо провести один и тот же набор GUI-тестов на разных браузерах.

Как завести Selenium Server

Сначала идем по адресу и качаем последнюю версию Selenium RC. В архиве будет много папочек с названиями типа selenium-dotnet-client-driver. В конце будет папочка selenium-server. Ее надо распаковать в какое-нибудь известное место. Selenium server запускается примерно такой командой:
start java -jar selenium-server.jar -multiWindow -debug -timeout 100000
Открывается консольное java-приложение, которое в начале напишет что-то вроде:
11:20:19.413 INFO - Java: Sun Microsystems Inc. 10.0-b19
11:20:19.433 INFO - OS: Windows XP 5.1 x86
11:20:19.433 INFO - v1.0-beta-1 [2201], with Core v1.0-beta-1 [1994]
Сервер должен работать на протяжении всех тестов.

Как написать тесты

Тесты будем писать на C#. Для организации тестов используется NUnit, так что его тоже надо будет сначала выкачать и поставить. Теперь создаем в Visual Studio проект Tests типа Class Library. В References надо добавить сборки nunit.framework и ThoughtWorks.Selenium.Core. Кроме того, нужно будет зайти в Properties проекта, пойти на вкладку Debug и указать в графе Start external program путь до nunit.exe, а в Command line arguments - Tests.dll. Это нужно для того, чтобы можно было запускать и отлаживать тесты прямо из Visual Studio. Теперь можно и писать тестовые классы. Наша задача состоит в том, чтобы одни и те же тесты выполнились на нескольких браузерах. Напишем следующий класс:
using NUnit.Framework;
using Selenium;

namespace Tests
{
  public abstract class GuiTestCommon
  {
    protected ISelenium selenium;
    protected static string browserString;

    protected virtual void ConfigureSelenium()
    {
      selenium = new DefaultSelenium("localhost", 4444, browserString, "http://www.google.ru");
      selenium.Start();
    }

    [SetUp]
    public void SetupTest()
    {
      ConfigureSelenium();
    }

    [TearDown]
    public void TeardownTest()
    {
      selenium.Stop();
    }

    [Test]
    public void GoogleSearch()
    {
      selenium.Open("/");
      Assert.AreEqual("Google", selenium.GetTitle());
      selenium.Type("q", "Selenium OpenQA");
      Assert.AreEqual("Selenium OpenQA", selenium.GetValue("q"));
      selenium.Click("btnI");
      selenium.WaitForPageToLoad("50000");
    }
  }
}
В коде, в принципе, все довольно понятно. Есть объект selenuim, посредством которого осуществляются все манипуляции в браузере. В SetupTest этот объект создается, в тесте GoogleSearch он идет в гугл, набирает там "Selenium OpenQA", нажимает кнопку "Мне повезет" и ждет какое-то время, пока страница загрузится. В конфигурации мы специально не указали конкретное значение browserString. Теперь можно унаследовать от данного класса отдельные классы для каждого интересующего нас браузера. Получим что-то вроде:
using NUnit.Framework;

namespace Tests
{
  [TestFixture]
  public class GuiTestFirefox : GuiTestCommon
  {
    protected override void ConfigureSelenium()
    {
      browserString = "*firefox";
      base.ConfigureSelenium();
    }
  }
}
Это класс, тестирующий Firefox. Аналогично можно написать для IE ("*iexplore") и еще много для чего.

Замечания

  • Кое-кто утверждает, что для Firefox browserString должна быть не "*firefox", а "*chrome". Тесты работает и так, и так, но говорят, что во втором случае не вылезает ошибка "Permission denied to get property Location.href". Спорить не буду, но на память запишу
  • Не следует в Open использовать абсолютные адреса. Так, вместо
    selenium.Open("http://www.google.ru")
    
    лучше написать
    selenium.Open("/")
    
    Опять же, по той же причине.
  • Слабое место Selenium - это всевозможные Wait (как то: WaitForPageToLoad, WaitForCondition и т.д.). Тут бывают баги. В частности, приведенный тест иногда не проходит в IE: выдается то таймаут, то, опять же, "Permission denied to get property Location.href"