Capítulo 13. PHPUnit e Selenium

Servidor Selenium

Servidor Selenium é uma ferramenta de testes que permite a você escrever testes automatizados de interface de usuário para aplicações web em qualquer linguagem de programação contra qualquer website HTTP usando um dos principais navegadores. Ele realiza tarefas automatizadas no navegador guiando seu processo através do sistema operacional. O Selenium executa os testes diretamente em um navegador, exatamente como os usuários reais fazem. Esses testes podem ser usados para ambos testes de aceitação (realizando testes de alto-nível no sistema integrado em vez de apenas testar cada unidade do sistema independentemente) e testes de compatibilidade de navegador (testando a aplicação web em diferentes sistemas operacionais e navegadores).

O único cenário suportado do PHPUnit_Selenium é o do servidor Selenium 2.x. O servidor pode ser acessado através da Api clássica Selenium RC, já presente no 1.x, ou com a API WebDriver (parcialmente implementada) do PHPUnit_Selenium 1.2.

A razão por trás dessa decisão é que o Selenium 2 é compatível e o Selenium RC não é mais mantido.

Instalação

Primeiro, instale o Servidor Selenium:

  1. Baixe um arquivo de distribuição do Servidor Selenium.
  2. Descompacte o arquivo de distribuição e copie o selenium-server-standalone-2.9.0.jar (verifique o sufixo da versão) para /usr/local/bin, por exemplo.
  3. Inicie o Servidor Selenium executando java -jar /usr/local/bin/selenium-server-standalone-2.9.0.jar.

O pacote PHPUnit_Selenium está incluso na distribuição PHAR do PHPUnit. Ele pode ser instalado através do Composer, adicionando a seguinte dependência "require-dev":

"phpunit/phpunit-selenium": ">=1.2"

Agora podemos enviar comandos para o Servidor Selenium usando seu protocolo cliente/servidor.

PHPUnit_Extensions_Selenium2TestCase

O caso de teste PHPUnit_Extensions_Selenium2TestCase permite a você usar a API WebDriver (parcialmente implementada).

Exemplo 13.1 mostra como testar os conteúdos do elemento <title> do site http://www.example.com/.

Exemplo 13.1: Exemplo de uso para PHPUnit_Extensions_Selenium2TestCase

<?php
class WebTest extends PHPUnit_Extensions_Selenium2TestCase
{
    protected function setUp()
    {
        $this->setBrowser('firefox');
        $this->setBrowserUrl('http://www.example.com/');
    }

    public function testTitle()
    {
        $this->url('http://www.example.com/');
        $this->assertEquals('Example WWW Page', $this->title());
    }

}
?>
phpunit WebTest
PHPUnit 4.7.0 by Sebastian Bergmann and contributors.

F

Time: 28 seconds, Memory: 3.00Mb

There was 1 failure:

1) WebTest::testTitle
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'Example WWW Page'
+'IANA — Example domains'

/home/giorgio/WebTest.php:13

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


Os comandos do Selenium2TestCase são implementados via __call(). Por favor, recorra ao teste de ponta a ponta para o PHPUnit_Extensions_Selenium2TestCase para uma lista de cada característica suportada.

PHPUnit_Extensions_SeleniumTestCase

A extensão de caso de teste PHPUnit_Extensions_SeleniumTestCase implementa o protocolo cliente/servidor para conversar com o Servidor Selenium assim como métodos de asserção especializados para testes web.

O Exemplo 13.2 mostra como testar os conteúdos do elemento <title> para o site http://www.exemplo.com/.

Exemplo 13.2: Exemplo de uso para PHPUnit_Extensions_SeleniumTestCase

<?php
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';

class WebTest extends PHPUnit_Extensions_SeleniumTestCase
{
    protected function setUp()
    {
        $this->setBrowser('*firefox');
        $this->setBrowserUrl('http://www.example.com/');
    }

    public function testTitle()
    {
        $this->open('http://www.example.com/');
        $this->assertTitle('Example WWW Page');
    }
}
?>
phpunit WebTest
PHPUnit 4.7.0 by Sebastian Bergmann and contributors.

F

Time: 9 seconds, Memory: 6.00Mb

There was 1 failure:

1) WebTest::testTitle
Current URL: http://www.iana.org/domains/example/

Failed asserting that 'IANA — Example domains' matches PCRE pattern "/Example WWW Page/".


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


Diferente da classe PHPUnit_Framework_TestCase, classes de caso de teste que estendem o PHPUnit_Extensions_SeleniumTestCase têm que fornecer um método setUp(). Esse método é usado para configurar a sessão do Servidor Selenium. Veja Tabela 13.1 para uma lista de métodos que estão disponíveis para isso.

Tabela 13.1. API do Servidor Selenium: Setup

MétodoSignificado
void setBrowser(string $browser)Define o navegador a ser usado pelo Servidor Selenium.
void setBrowserUrl(string $browserUrl)Define a URL base para os testes.
void setHost(string $host)Define o nome do host para a conexão do Servidor Selenium.
void setPort(int $port)Define a porta de conexão para o Servidor Selenium
void setTimeout(int $timeout)Define o tempo de espera para a conexão do Servidor Selenium.
void setSleep(int $seconds)Define o número de segundos que o cliente do Servidor Selenium deve esperar entre cada envio de comandos de ação para o Servidor Selenium.


O PHPUnit pode opcionalmente capturar a tela quando um teste do Selenium falha. Para habilitar isso, configure $captureScreenshotOnFailure, $screenshotPath e $screenshotUrl em sua classe de caso de teste como mostrado em Exemplo 13.3.

Exemplo 13.3: Capturando a tela quando um teste falha

<?php
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';

class WebTest extends PHPUnit_Extensions_SeleniumTestCase
{
    protected $captureScreenshotOnFailure = TRUE;
    protected $screenshotPath = '/var/www/localhost/htdocs/screenshots';
    protected $screenshotUrl = 'http://localhost/screenshots';

    protected function setUp()
    {
        $this->setBrowser('*firefox');
        $this->setBrowserUrl('http://www.example.com/');
    }

    public function testTitle()
    {
        $this->open('http://www.example.com/');
        $this->assertTitle('Example WWW Page');
    }
}
?>
phpunit WebTest
PHPUnit 4.7.0 by Sebastian Bergmann and contributors.

F

Time: 7 seconds, Memory: 6.00Mb

There was 1 failure:

1) WebTest::testTitle
Current URL: http://www.iana.org/domains/example/
Screenshot: http://localhost/screenshots/334b080f2364b5f11568ee1c7f6742c9.png

Failed asserting that 'IANA — Example domains' matches PCRE pattern "/Example WWW Page/".


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


Você pode executar cada teste usando um conjunto de navegadores: Em vez de usar setBrowser() para configurar um navegador, você pode declarar um vetor public static chamado $browsers em sua classe de caso de testes. Cada item nesse vetor descreve uma configuração de navegador. Cada um desses navegadores pode ser hospedado em diferentes Servidores Selenium. O Exemplo 13.4 mostra um exemplo.

Exemplo 13.4: Definindo configurações de múltiplos navegadores

<?php
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';

class WebTest extends PHPUnit_Extensions_SeleniumTestCase
{
    public static $browsers = array(
      array(
        'name'    => 'Firefox on Linux',
        'browser' => '*firefox',
        'host'    => 'my.linux.box',
        'port'    => 4444,
        'timeout' => 30000,
      ),
      array(
        'name'    => 'Safari on MacOS X',
        'browser' => '*safari',
        'host'    => 'my.macosx.box',
        'port'    => 4444,
        'timeout' => 30000,
      ),
      array(
        'name'    => 'Safari on Windows XP',
        'browser' => '*custom C:\Program Files\Safari\Safari.exe -url',
        'host'    => 'my.windowsxp.box',
        'port'    => 4444,
        'timeout' => 30000,
      ),
      array(
        'name'    => 'Internet Explorer on Windows XP',
        'browser' => '*iexplore',
        'host'    => 'my.windowsxp.box',
        'port'    => 4444,
        'timeout' => 30000,
      )
    );

    protected function setUp()
    {
        $this->setBrowserUrl('http://www.example.com/');
    }

    public function testTitle()
    {
        $this->open('http://www.example.com/');
        $this->assertTitle('Example Web Page');
    }
}
?>


PHPUnit_Extensions_SeleniumTestCase pode coletar a informação de cobertura de código para execução de testes através do Selenium:

  1. Copie PHPUnit/Extensions/SeleniumCommon/phpunit_coverage.php dentro do seu diretório raiz de documentos do servidor web.
  2. Em seu arquivo de configuração php.ini do servidor web, configure PHPUnit/Extensions/SeleniumCommon/prepend.php e PHPUnit/Extensions/SeleniumCommon/append.php como o auto_prepend_file e auto_append_file, respectivamente.
  3. Na sua classe de caso de teste que estende PHPUnit_Extensions_SeleniumTestCase, use
    protected $coverageScriptUrl = 'http://host/phpunit_coverage.php';
    para configurar a URL para o script phpunit_coverage.php.

Tabela 13.2 lista os vários métodos de asserção que o PHPUnit_Extensions_SeleniumTestCase fornece.

Tabela 13.2. Asserções

AsserçãoSignificado
void assertElementValueEquals(string $locator, string $text)Relata um erro se o valor do elemento identificado por $locator não é igual ao $text informado.
void assertElementValueNotEquals(string $locator, string $text)Relata um erro se o valor do elemento identificado por $locator é igual ao $text informado.
void assertElementValueContains(string $locator, string $text)Relata um erro se o valor do elemento identificado por $locator não contém o $text informado.
void assertElementValueNotContains(string $locator, string $text)Relata um erro se o valor do elemento identificado por $locator contém o $text informado.
void assertElementContainsText(string $locator, string $text)Relata um erro se o elemento identificado por $locator não contém o $text informado.
void assertElementNotContainsText(string $locator, string $text)Relata um erro se o elemento identificado por $locator contém o $text informado.
void assertSelectHasOption(string $selectLocator, string $option)Relata um erro se a opção informada não estiver disponível.
void assertSelectNotHasOption(string $selectLocator, string $option)Relata um erro se a opção informada estiver disponível.
void assertSelected($selectLocator, $option)Relata um erro se o rótulo informado não estiver selecionado.
void assertNotSelected($selectLocator, $option)Relata um erro se o rótulo informado estiver selecionado.
void assertIsSelected(string $selectLocator, string $value)Relata um erro se o valor informado não estiver selecionado.
void assertIsNotSelected(string $selectLocator, string $value)Relata um erro se o valor informado estiver selecionado.


Tabela 13.3 mostra o método modelo de PHPUnit_Extensions_SeleniumTestCase:

Tabela 13.3. Métodos Modelo

MétodoSignificado
void defaultAssertions()Sobreposição para realizar asserções que são compartilhadas por todos os testes de um caso de teste. Este método é chamado após cada comando ser enviado ao Servidor Selenium.


Por favor, verifique a documentação dos comandos do Selenium para uma referência de todos os comandos disponíveis e como eles são utilizados.

Os comandos do Selenium 1 são implementados dinamicamente via __call. Verifique também a documentação da API para PHPUnit_Extensions_SeleniumTestCase_Driver::__call() para uma lista de todos os métodos suportados do lado do PHP, juntamente com argumentos e tipos de retorno quando disponíveis.

Usando o método runSelenese($filename) você também pode executar um teste Selenium a partir de sua especificação Selenese/HTML. Além disso, usando o atributo estático $seleneseDirectory, você pode criar automaticamente objetos de teste a partir de um diretório que contenha arquivos Selenese/HTML. O diretório especificado é pesquisado recursivamente por arquivos .htm que possam conter Selenese/HTML. O Exemplo 13.5 mostra um exemplo.

Exemplo 13.5: Usando um diretório de arquivos Selenese/HTML como testes

<?php
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';

class SeleneseTests extends PHPUnit_Extensions_SeleniumTestCase
{
    public static $seleneseDirectory = '/path/to/files';
}
?>


Desde o Selenium 1.1.1, um recurso experimental foi incluído para permitir ao usuário compartilhar a sessão entre testes. O único caso suportado é compartilhar a sessão entre todos os testes quando um único navegador é usado. Chame PHPUnit_Extensions_SeleniumTestCase::shareSession(true) em seu arquivo bootstrap para habilitar o compartilhamento de sessão. A sessão será reiniciada no caso de testes mal-sucedidos (falhos ou incompletos); cabe ao usuário evitar interações entre testes seja resetando cookies ou deslogando da aplicação sob teste (com um método tearDown()).

Por favor, abra um chamado no GitHub para sugerir melhorias para esta página. Obrigado!