Как стать автором
Обновить

История одного дня: PHPUnit, Selenium, Facebook

Чулан
Сегодня я хочу рассказать о том как я мучался с PHPUnit, Selenium RC и Facebook'ом :)

Итак, мне была дана задача сделать систему ежедневного тестирования сайта и постинга багов в bugzill'у (Расскажу я только о связке PHPUnit/Selenium RC). Воспользовавшись немного гуглом я нашел две вещи подходящие для php — SimpleTest и PHPUnit. Покурив доки я остановился на PHPUnit. Выбор пал именно на него из-за поддержки Selenium'a.
Т.к. ранее ни с PHPUnit, ни с Selenium я не работал, то пришлось искать что почитать (также большое спасибо пользователю WanderingStar за статью Юнит-тестирование в PHP). Начитавшись до красных глаз, решил сделать первый тест :) Но сначала необходимо все установить:

pear channel-discover pear.phpunit.de
pear install phpunit/PHPUnit-beta


Далее скачиваем Selenium RC (selenium-remote-control-1.0.1-dist.zip), распаковываем и в директории selenium-server-1.0.1 запускаем:

java -jar selenium-server.jar

Теперь приступим к написанию. Первый тест как всегда был взят из документации:

  1. <?php
  2. require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
  3. class WebTest extends PHPUnit_Extensions_SeleniumTestCase
  4. {
  5.   protected function setUp()
  6.   {
  7.     $this->setBrowser('*firefox');
  8.     $this->setBrowserUrl('http://www.example.com/');
  9.   }
  10.   public function testTitle()
  11.   {
  12.     $this->open('http://www.example.com/');
  13.     $this->assertTitleEquals('Example WWW Page');
  14.   }
  15. }
  16. ?>
* This source code was highlighted with Source Code Highlighter.


Сохраняем в файл WebTest.php и запускаем: phpunit WebTest

Видим как запустился FireFox, открыл страничку и убился :) Результат выполнения теста:
PHPUnit 3.4.0beta4 by Sebastian Bergmann.

E

Time: 14 seconds

There was 1 error:

1) WebTest::testTitle
BadMethodCallException: Method assertTitleEquals not defined.
WebTest.php:15

FAILURES!
Tests: 1, Assertions: 0, Errors: 1.


Ошибка… Не хорошо писать код с ошибками в документации… Вспомнив что это бета релиз, пошел проверить changelog. Обнаружил интересную вещь:
Please note that the following commands had to be renamed:

assertAlertPresent() has been renamed to assertAlert()
assertNoAlertPresent() has been renamed to assertNotAlert()
assertNoConfirmationPresent() has been renamed to assertConfirmationNotPresent()
assertLocationEquals() has been renamed to assertLocation()
assertLocationNotEquals() has been renamed to assertNotLocation()
assertNoPromptPresent() has been renamed to assertPromptNotPresent()
assertNothingSelected() has been renamed to assertNotSomethingSelected()
assertTitleEquals() has been renamed to assertTitle()
assertTitleNotEquals() has been renamed to assertNotTitle()


Исправляем assertTitleEquals на assertTitle и заново запускаем:
PHPUnit 3.4.0beta4 by Sebastian Bergmann.

F

Time: 9 seconds

There was 1 failure:

1) WebTest::testTitle
Current URL: www.example.com

Failed asserting that <string:Example Web Page> matches PCRE pattern "/Example WWW Page/".
WebTest.php:15

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.


Вот и отличненько, тест сработал. получилась ошибка. Далее хотелось бы сохранить скриншот ошибки. Вносим изменения в код:

  1. <?php
  2. require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
  3. class WebTest extends PHPUnit_Extensions_SeleniumTestCase
  4. {
  5.    protected $captureScreenshotOnFailure = TRUE;
  6.    protected $screenshotPath = 'd:\apache2\htdocs\screenshots';
  7.    protected $screenshotUrl = 'http://localhost/screenshots';
  8.  
  9.    protected function setUp()
  10.    {
  11.      $this->setBrowser('*firefox');
  12.      $this->setBrowserUrl('http://www.example.com/');
  13.    }
  14.    public function testTitle()
  15.    {
  16.      $this->open('http://www.example.com/');
  17.      $this->assertTitle('Example WWW Page');
  18.    }
  19. }
  20. ?>
* This source code was highlighted with Source Code Highlighter.


Запускаем:

PHPUnit 3.4.0beta4 by Sebastian Bergmann.

F

Time: 8 seconds

There was 1 failure:

1) WebTest::testTitle
Current URL: www.example.com
Screenshot: localhost/screenshots/ed26432dcfb69cbbdd4e0c01fade4682.png

Failed asserting that <string:Example Web Page> matches PCRE pattern "/Example WWW Page/".
WebTest.php:19

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.


Вот так уже лучше. Пример из документации заработал :) Хотелось бы перейти к тестированию разрабатываемого сайта. Не вдаваясь в подробности сайт похож чем-то на Yahoo Answers с авторизацией через Facebook. Вот тут нас и ждет косяк…

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

Код:
  1. <a onclick="FB.Connect.requireSession(function() { window.location='index.php'; }); return false;" href="#">
  2. <img alt="Connect" src="http://static.ak.fbcdn.net/images/fbconnect/login-buttons/connect_light_medium_long.gif" id="fb_login_image"/>
  3. </a>
* This source code was highlighted with Source Code Highlighter.


После клика по этой кнопке пользователь видит PopUp:


Selenium предоставляет возможность кликнуть по элементу, для этого надо знать его id или name (также возможен поиск при помощи xpath, но мне он не подходит, т.к. элемент могут передвинуть). Как вы видите у тега id отсутствует (исправить код сайта временно нельзя). Пришлось искать другие варианты авторизации. Погуглив немного я наткнулся на такой вариант. Вкратце мы проходим авторизация на facebook'e и получаем куки, которые мы подсовываем Selenium'у. Реализовать мне это не удалось, т.к. я вспомнил что даже если пользователь авторизован на facebook'e, ему все равно надо кликнуть по кнопке «Connect with Facebook». Тут я ушел покурить :)

На балконе мне в голову пришла идея — а почему бы не кликнуть по картинке, ведь ее id у нас есть. Решил попробовать (правда сомневался что заработает, ведь onclick висит не на картинке, но других идей не было). Вот что я накодил:

  1. <?php
  2.  
  3. require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
  4.  
  5. class LoginTest extends PHPUnit_Extensions_SeleniumTestCase
  6. {
  7.  protected $captureScreenshotOnFailure = TRUE;
  8.  protected $screenshotPath = 'd:\apache2\htdocs\screenshots';
  9.  protected $screenshotUrl = 'http://localhost/screenshots';
  10.  
  11.  protected function setUp()
  12.  {
  13.   $this->setBrowser('*firefox');
  14.   $this->setBrowserUrl('http://%site_url%/');
  15.  }
  16.  
  17.  public function testTitle()
  18.  {
  19.   $this->open('/');
  20.   
  21.   //Click Login
  22.   $this->click("fb_login_image");
  23.  }
  24. }
  25.  
  26. ?>
* This source code was highlighted with Source Code Highlighter.


Каково же было мое удивление, когда это заработало… Теперь нам надо ввести email и пароль и нажать Connect. Id этих элементов нам известны — email, pass, login. Делаем такой код:

  1. <?php
  2.  
  3. require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
  4.  
  5. class LoginTest extends PHPUnit_Extensions_SeleniumTestCase
  6. {
  7.  protected $captureScreenshotOnFailure = TRUE;
  8.  protected $screenshotPath = 'd:\apache2\htdocs\screenshots';
  9.  protected $screenshotUrl = 'http://localhost/screenshots';
  10.  
  11.  protected function setUp()
  12.  {
  13.   $this->setBrowser('*firefox');
  14.   $this->setBrowserUrl('http://%site_url%/');
  15.  }
  16.  
  17.  public function testTitle()
  18.  {
  19.   $this->open('/');
  20.   
  21.   //Click Login
  22.   $this->click("fb_login_image");
  23.  
  24.   $this->type("email", "test@test.com");
  25.   $this->type("pass", "паролъ");
  26.   $this->click("login");
  27.  
  28.  }
  29. }
  30.  
  31. ?>
* This source code was highlighted with Source Code Highlighter.


Результат:
PHPUnit 3.4.0beta4 by Sebastian Bergmann.

E

Time: 25 seconds

There was 1 error:

1) WebTest::testTitle
RuntimeException: Response from Selenium RC server for testComplete().
ERROR: Element email not found.

WebTest.php:32

FAILURES!
Tests: 1, Assertions: 1, Errors: 1.


Как так? Он же есть… Немного подумав я все-таки понял почему нету. Этот элемент находиться в PopUp'е а не в главном окне. Поискав в документации как организовать переключение между окнами я получил конечный результат кода:

  1. <?php
  2.  
  3. require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
  4.  
  5. class LoginTest extends PHPUnit_Extensions_SeleniumTestCase
  6. {
  7.  protected $captureScreenshotOnFailure = TRUE;
  8.  protected $screenshotPath = 'd:\apache2\htdocs\screenshots';
  9.  protected $screenshotUrl = 'http://localhost/screenshots';
  10.  
  11.  protected function setUp()
  12.  {
  13.   $this->setBrowser('*firefox');
  14.   $this->setBrowserUrl('http://%site_url%/');
  15.  }
  16.  
  17.  public function testTitle()
  18.  {
  19.   //Открываем главную страницу
  20.   $this->open('/');
  21.   //Проверяем заголовок (на тот ли сайт мы попали?)
  22.   $this->assertTitle('%page_title%');
  23.   
  24.   //Кликаем логин
  25.   $this->click("fb_login_image");
  26.   //Ждем пока вылезет popup
  27.   $this->waitForPopUp("_blank", "30000");
  28.   
  29.   //Выбираем наш popup
  30.   $this->selectWindow("_blank");
  31.   
  32.   //заполняем поля и кликаем Connect
  33.   $this->type("email", "test@test.com");
  34.   $this->type("pass", "паролъ");
  35.   $this->click("login");
  36.  
  37.   //Выбираем главное окно
  38.   $this->selectWindow("null");
  39.   //Ждем пока оно загрузится
  40.   $this->waitForPageToLoad("30000");
  41.   
  42.   //Проверяем заголовок
  43.   $this->assertTitle('%page_title%');
  44.   
  45.   //Проверяем залогинились или нет (существует ли текст signout на странице)
  46.   $this->verifyTextPresent('signout');
  47.  }
  48. }
* This source code was highlighted with Source Code Highlighter.


Всем спасибо за внимание :) Любая критика приветсвуеться.

З.Ы. Сильно не пинайте, первый пост все-таки. Если статьи такого плана интересны, могу еще написать о чем-нибудь.

Теги:
Хабы:
Всего голосов 11: ↑10 и ↓1 +9
Просмотры 2K
Комментарии Комментарии 20