terça-feira, 19 de outubro de 2010

Projeto de Integracao Selenium x Mantis x Testlink

Olá Pessoal!
Como último post sobre a Integração com o Selenium e ferramentas de Gestão de Teste e Gestão de Defeitos criei um projeto em Java que integra o Selenium, Mantis e Testlink.

É recomendado você ler os dois post's abaixo:

Se você já leu estes dois tutoriais, continue lendo este post...
Este projeto de exemplo vai:
  • Executar um script de teste no Selenium RC
    • O script de teste irá falhar
  • Reportar um bug no Mantis anexando uma imagem do browser no momento do erro
  • Reportar o resultado do teste (que será com falha) ao Testlink
  • Associar o bug aberto ao Caso de Teste no Testlink
Abaixo será apresentado somente as modificações executadas para a criação de um exemplo único. Se você precisar de mais explicações sobre algum item da integração, por favor, consulte os post's anteriores.

1. Organização
Este projeto foi dividido nos seguintes pacotes, conforme descrito abaixo:
  •  com.blogspot.sembugs.mantis
    • ConnectMantis.java: Classe que faz a conexão com o Mantis
    • MantisReport.java: Classe que reporta o bug no Mantis
  • com.blogspot.sembugs.test
    • CasoTeste.java: Caso de Teste de exemplo
  • com.blogspot.sembugs.testlink
    • ResultadoExecucao.java: Classe que reporta o resultado da execução do teste
  • com.blogspot.sembugs.util
    • IConstantes.java: Interface com dados comuns as classes

2. Modificações
A seguir serão apresentados os trechos das classes que foram alterados e os devidos comentários sobre as alterações

MantisReport.java
Nesta classe foram feitas as seguintes alterações:
  • Linha 1: Mudança do método, que agora tem como retorno um String.
  • Linha 8: Criado um atributo local do tipo long para retornar o ID do bug cadastrado
  • Linha 12: O atributo local é transformado em uma String e atribuido a variável bugID
  • Linha 22: Adicionado o retorno do método

PS: A classe abaixo está omitindo uma série de linhas de código, sendo apresentado apenas as mais relevantes perante as alterações.

1:  public static String reporIssue(String sumario, String descricao, String categoria, String informacaoAdicional, String evidencia, String nomeArquivo) {  
2:          IMCSession sessao = null;  
3:          String arquivo = nomeArquivo + ".png";  
4:          String bugID = null;  
5:            
6:          try {  
7:        // submete o bug no Mantis  
8:        long id = sessao.addIssue(issue);     
9:        sessao.addIssueAttachment(id, arquivo, "image/png", Base64.decodeBase64(evidencia));  
10:          
11:        // retorna o ID do bug como String, para fazer o relacionanmento do bug com o Testlink  
12:        bugID = String.valueOf(id);  
13:          
14:          } catch (MalformedURLException e) {  
15:              System.err.println("Erro na URL de acesso ao Mantis");  
16:              e.printStackTrace();  
17:          } catch (MCException e) {  
18:              System.err.println("Erro na comunicacao com o Mantis");  
19:              e.printStackTrace();  
20:          }  
21:            
22:      return bugID;  
23:      }  
24:  }  


ResultadoExecucao.java
Nesta classe foram feitas as seguintes alterações:
  • Linha 1: Foi adicionado um novo parâmetro para a utilização do método: Integer bugID. É esperado que seja passado o ID do bug cadastrado para fazer a associação com o Testlink, mas não é obrigatório
  • Linha 5: Um verificação é feita para ver se o ID do bug será passado. Se sim há uma séria de atributos que são obtidos para que o resultado de execução do caso de teste contenha o bug associado. Isso foi adicionado porque o método da API do Testlink tem uma assinatura (parâmetros) diferente do do método que não associa o bug
  • Linhas 7, 8, 9 e 10: Todos os atributos locais necessários para a associação do bug no resultado do caso de teste.
  • Linha 12: Envio dos dados de resultado do teste ao Testlink utilizando o ID do bug para associação.
  • Linhas 13 e 14: Se o bug não for passado (for null) o envio do resultado de execução para o Testlink utiliza outro método para esta tarefa.

1:  public static void reportTestCaseResult(String projetoTeste, String planoTeste, String casoTeste, String nomeBuild, String nota, String resultado, Integer bugID) throws TestLinkAPIException {  
2:        
3:    TestLinkAPIClient testlinkAPIClient = new TestLinkAPIClient(DEVKEY, URL);  
4:        
5:    if (bugID != null) {  
6:            
7:      Integer projectID = TestLinkAPIHelper.getProjectID(testlinkAPIClient, PROJETO_TESTLINK);  
8:      Integer testPlanID = TestLinkAPIHelper.getPlanID(testlinkAPIClient, projectID, PLANO);  
9:      Integer testCaseID = TestLinkAPIHelper.getTestCaseID(testlinkAPIClient, projectID, CASO_TESTE1);  
10:     Integer buildID = TestLinkAPIHelper.getBuildID(testlinkAPIClient, testPlanID, nomeBuild);  
11:    
12:     testlinkAPIClient.reportTestCaseResult(testPlanID, testCaseID, buildID, bugID, false, nota, resultado);          
13:    } else {  
14:        testlinkAPIClient.reportTestCaseResult(projetoTeste, planoTeste, casoTeste, nomeBuild, nota, resultado);  
15:    }  
16:  }  


CasoTeste.java
Esta classe é a mesma utilizado nos outros dois tutoriais, porém com nome diferente.
Basicamente foi alterado apenas o bloco finnally do script.
  • Linha 3: Foi adicionado o método para o report do bug, atribuindo para uma variável o ID do bug que foi adicionado.
  • Linha 5: Adicionado o novo método com o parâmetro do bugID, para que o bug seja associado ao resultado de execução do caso de teste.

PS: A classe abaixo está omitindo uma série de linhas de código, sendo apresentado apenas as mais relevantes perante as alterações.

1:  } finally {  
2:    if (erro) {  
3:      String bugID = MantisReport.reporIssue("Erro no Caso de Teste de Pesquisa de Livros", "Erro em alguma validacao ou validacao", "Automacao", msgErro, evidenciaErro, "CasoTesteMantisNOK");  
4:                    
5:      ResultadoExecucao.reportTestCaseResult(PROJETO_TESTLINK, PLANO, CASO_TESTE1, BUILD, msgErro, resultado, Integer.parseInt(bugID));      
6:            
7:      CasoTeste.fail(msgErro);  
8:    }  
9:  }  


3. Baixando o código-fonte
O projeto completo e funcional pode ser baixado no link abaixo (18 MB):

http://www.eliasnogueira.com/arquivos_blog/selenium/integracao/mantis_testlink/selenium-integration.zip


4. Verificando online o resultado de execução
Se você baixar o projeto e já executá-lo ( ) poderá ver que os resultados no Testlink e Mantis serão colocados em ambas aplicações que tenho online.

Para acessar ambos, utilize os seguintes dados de login:
  • Usuário: convidado
  • Senha: convidado
Dentro do Mantis, que está acessível pela URL abaixo, você verá que o bug será reportado contendo os dados que passamos para o método utilizado na classe CasoTeste.java. Atente-se para o ID do bug e o horário de criação:

http://www.eliasnogueira.com/arquivos_blog/mantisbt-1.2.3/


Agora no Testlink, que está acessível pela URL abaixo, veremos que o resultado reportado foi com falha, está dentro do mesmo horário de criação do bug e tem o bug associado, conforme figura.



Bom pessoal, por enquanto é isso! Abraço a todos!

sexta-feira, 15 de outubro de 2010

Integração Selenium e Mantis

For foreing raders, please clique here to read this post in english (google translator)

Não deixe de ler também a Integração do Selenium e Testlink.

Escopo
Este tutorial vai apresentar como efetuar a integração entre o Selenium RC e o Mantis, para que seja possível reportar automaticamente um bug quando um erro em um script do Selenium falhar.

Criaremos um projeto em Java com o suporte do JUnit para a criação do script de teste com o Selenium. abaixo há uma lista de itens necessários para esse tutorial.

O que é necessário?

2. Preparando seu ambiente de Desenvolvimento
A preparação do ambiente vai apresentar somente as bibliotecas necessárias para fazer a integração funcionar. Não é intuito deste item ensinar alguma coisa sobre o Eclipse ou sobre Java.

2.1 Selecionando as bibliotecas necessárias
Para rodar o script de teste com a integração e necessário os seguintes arquivos (bibliotecas e libraries) das seguintes API's / frameworks:
  • mantisconnect: necessário adicionar as seguintes bibliotecas
    • mantisconnect-client-api-1.1.1.0.jar
    • todas as libs, exeto a junit, da pasta lib
  • Selenium RC: necessário adicionar as seguintes bibliotecas
    • selenium-server.jar
    • selenium-java-client-driver.jar
  • JUnit: necessário adicionar o JUnit 4 que já vem com o Eclipse (Add Libraries)
Abaixo segue a imagem das bibliotecas que foram adicionadas ao Eclipse.


 Para adicionar cada biblioteca você precisa clicar com o botão direito no nome do projeto e selecionar Build Path/Configure Build Path...



Adicone também a biblioteca do JUnit, indo ao mesmo local (Configure Build Path...) e clicando no botão Add Library. Selecione JUnit e, em seguida, JUnit 4.

 2.1 Desenvolvendo o código-fonte
A aplicação de exemplo, que está no final do post traz o código-fonte do script de teste e mais dois arquivos de código-fonte, que serão explicados abaixo.

A primeira coisa a fazer é entender o script de teste primeiro. O package, os imports e comentários em javadoc foram excluídos para exemplificar o funcionamento da classe.
Existem duas classes de teste, uma com execução OK e outra que forçará o erro para que seja possível o report automático do bug.
Abaixo será apresentado o script que força o erro.

1:  public class CasoTesteMantisNOK extends TestCase implements IConstantes {  
2:      
3:    Selenium selenium;  
4:    SeleniumServer server;  
5:      
6:    String serverHost = "localhost";  
7:    int serverPort = 4444;  
8:    String browserStartCommand = "*firefox";  
9:    String browserURL = "http://www.lojaexemplodelivros.com.br/";  
10:      
11:    boolean erro;  
12:    String msgErro;  
13:    String evidenciaErro;  
14:      
15:    public void setUp() throws Exception {  
16:      selenium = new DefaultSelenium(serverHost, serverPort, browserStartCommand, browserURL);  
17:      server = new SeleniumServer();  
18:        
19:      server.start();  
20:      selenium.start();  
21:    }  
22:      
23:    @Test  
24:    public void testPesquisaLivro() throws Exception {  
25:        
26:      try {  
27:        selenium.open("/");  
28:        selenium.click("//ul[@id='nav']/li[1]/ul/li[2]/ul/li[1]/a/span");  
29:        selenium.waitForPageToLoad("30000");  
30:          
31:        assertEquals("3 Item(s)", selenium.getText("//div[@id='main']/table[1]/tbody/tr/td[1]/strong"));  
32:        assertEquals("[PRODUTO] - Use a Cabeça! Java", selenium.getText("link=[PRODUTO DE EXEMPLO] - Use a Cabeça! Java"));  
33:        assertEquals("[PRODUTO DE EXEMPLO] - Entendendo e Dominando o Java: para Internet", selenium.getText("link=[PRODUTO DE EXEMPLO] - Entendendo e Dominando o Java: para Internet"));  
34:        assertEquals("[PRODUTO DE EXEMPLO] - Ajax com Java", selenium.getText("link=[PRODUTO DE EXEMPLO] - Ajax com Java"));  
35:          
36:        selenium.click("//img[@alt='[PRODUTO DE EXEMPLO] - Ajax com Java']");  
37:        selenium.waitForPageToLoad("30000");  
38:        assertTrue(selenium.isTextPresent("2x R$ 222,25 sem juros"));  
39:        assertTrue(selenium.isTextPresent("3x R$ 148,17 sem juros"));  
40:        assertTrue(selenium.isTextPresent("4x R$ 111,13 sem juros"));  
41:        assertTrue(selenium.isTextPresent("5x R$ 88,90 sem juros"));  
42:        
43:      } catch (AssertionError e) {  
44:        reportError(e);  
45:          
46:      } catch (Exception e) {  
47:        reportError(e);  
48:          
49:      } finally {  
50:        if (erro) {  
51:          MantisReport.reporIssue("Erro no Caso de Teste de Pesquisa de Livros", "Erro em alguma validacao ou validacao", "General", msgErro, evidenciaErro, "CasoTesteMantisNOK");  
52:          CasoTesteMantisNOK.fail(msgErro);  
53:        }  
54:      }  
55:    }  
56:      
57:    private void reportError(Throwable e) {      
58:      erro = true;  
59:      msgErro = e.getMessage();  
60:      e.printStackTrace();  
61:      evidenciaErro = selenium.captureEntirePageScreenshotToString("background=#FFFFFF");  
62:    }  
63:      
64:    public void tearDown() throws Exception {  
65:      selenium.stop();  
66:      server.stop();  
67:    }  
68:  }  


Basicamente há a criação dos atributos do Selenium e SeleniumServer para a execução, os métodos setup() e tearDown() do JUnit e o caso de teste automatizado.
Note que o bloco do caso de teste (método testPesquisaLivro) está com um try-catch. Isso é necessário para que possamos reportar um bug quando o script falhar.

Nas linhas 11, 12 e 13 foram criados atributos que controlarão os dados para o erro, e serão descritos logo mais.

A linha 32 deste script irá falhar, propositalmente, para que o bug seja reportado. O trecho de código correto (que não causará um bug) é o abaixo e também esta no arquivo CasoTesteMantisOK:

assertEquals("[PRODUTO DE EXEMPLO] - Use a Cabeça! Java", selenium.getText("link=[PRODUTO DE EXEMPLO] - Use a Cabeça! Java"));

Existem 2 blocos com catch (um iniciando na linha 43 e outro na linha 46). Foram colocados dois somente para distinguir o tipo do erro, se um erro na validação (AssertionError) ou qualquer erro (Exception). Dentro destes blocos há um método chamado reportError passando como parâmetro a exception.
Este método (linhas 57 a 62) informa através da variável erro que um erro ocorreu (passando true). Pega a mensagem de erro e coloca no atributo msgErro, faz com que a exception seja apresentada o console (e.printStackTrace()) e captura a imagem da página utilizando a função captureEntirePageScreenshotToString() para passar a imagem em formato de String Base64.

PS: esse comando só funcionará rodando com a angine do Mozilla (Firefox) e no Google Chrome. Caso queira que o mesmo comando funcione no IE leia este post (em inglês).

Na linha 50 e feito uma condição para ver se ocorreu algum erro (se o atributo erro está como true), caso positivo a função de report do bug é chamada.

A linha 51 apresenta a função utilizada para reportar o bug, que será explicado logo mais. Neste momento você só precisa saber que é necessário informar os seguintes dados (nesta ordem) para o método:
  • Sumário do bug
  • Descrição do bug
  • Categoria do bug
  • Informação adicional do bug
  • Evidencia (como String Base64)
  • Nome do arquivo (que será anexado)
A linha 52 força uma falha no script mostrando a mensagem de erro ocorrida.

Classe MatisReport
Dentro do projeto no pacote com.blogspot.sembugs há a classe MantisReport, que é a responsável por reportar o bug no Mantis. Eu gerei essa classe como chamada de uma função da API mantisconnect.

PS: package, imports e comentários em javadoc foram excluídos para exemplificar o funcionamento da classe.

1:  public class MantisReport implements IConstantes {  
2:    
3:      public static void reporIssue(String sumario, String descricao, String categoria, String informacaoAdicional, String evidencia, String nomeArquivo) {  
4:          IMCSession sessao = null;  
5:          String arquivo = nomeArquivo + ".png";  
6:            
7:          try {  
8:              sessao = ConnectMantis.getSessao();  
9:              IProject projeto = sessao.getProject(PROJETO);  
10:                
11:        Issue issue = new Issue();  
12:          
13:        issue.setProject(new MCAttribute(projeto.getId(), projeto.getName()));  
14:        issue.setAdditionalInformation(null);  
15:        issue.setOs(System.getProperty("os.name"));  
16:        issue.setOsBuild(System.getProperty("os.version"));  
17:        issue.setPlatform(System.getProperty("os.arch"));  
18:        issue.setSeverity(new MCAttribute(70, "crash"));  
19:        issue.setReproducibility(new MCAttribute(10, "always"));  
20:        issue.setSummary(sumario + new Date());  
21:        issue.setDescription(descricao);  
22:        issue.setCategory(categoria);  
23:        issue.setPriority(new MCAttribute(40, "high"));  
24:        issue.setAdditionalInformation(informacaoAdicional);  
25:          
26:        long id = sessao.addIssue(issue);     
27:        sessao.addIssueAttachment(id, arquivo, "image/png", Base64.decodeBase64(evidencia));  
28:                
29:          } catch (MalformedURLException e) {  
30:              System.err.println("Erro na URL de acesso ao Mantis");  
31:              e.printStackTrace();  
32:          } catch (MCException e) {  
33:              System.err.println("Erro na comunicacao com o Mantis");  
34:              e.printStackTrace();  
35:          }  
36:      }  
37:  }  

A linha 5 cria um atributo que pega o nome do arquivo, que foi passado como parâmetro, e concatena a extensão ".png", que será necessário para anexar o arquivo no Mantis.

Na linha 8 é feita uma chamada para o Singleton (que será explicado depois) para fazer a conexão com o Mantis e retornar um objeto de sessão do Mantis (IMSession)

A linha 9 traz o projeto, que está na interface IConstantes, como objeto de projeto do Mantis (IProject). Isso é necessário para sabermos em qual projeto reportar o bug.

Na linha 11 é criado uma issue (bug). A classe Issue representa um relato de bug.
A linha 13 seta o projeto que reportaremos o bug e das linhas 14 a 24 passamos diversas informações do bug para o Mantis. Existe uma série de informações que podemos passar, eu coloquei apenas as mais relevantes aqui.

Atenção: na linha 20 eu concatenei o sumário com a data atual (issue.setSummary(sumario + new Date());). Fiz isso para que seja possível executar diversas vezes o script sem duplicar o nome do bug no Mantis.

Note que nas linhas 18, 19 e 23 é preciso criar um objeto MCAttibute para que seja possível passar informações de qualquer atributo no report do bug como Severidade, Prioridade e Frequencia.
Serão sempre duas informações: o código e o nome do atributo.
Você pode consultar o código e nome dos atributos no arquivo config_defaults_inc.php e consultar cada atributo.
Se você quiser visualizar ou alterar estes atributos que estão no código-fonte, dê uma olhada nos atributos abaixo que estão contidos no arquivo citado acima:

1:  $g_severity_enum_string    = '10:feature,20:trivial,30:text,40:tweak,50:minor,60:major,70:crash,80:block';  
2:    
3:  $g_priority_enum_string    = '10:none,20:low,30:normal,40:high,50:urgent,60:immediate';  
4:    
5:  $g_reproducibility_enum_string = '10:always,30:sometimes,50:random,70:have not tried,90:unable to duplicate,100:N/A';  

Na linha 26 o bug é submetido para o cadastro, retornando o código do bug.

A linha 27 adiciona um anexo no bug, que é a tela capturada pelo Selenium no momento do erro. Para isso é necessário passar para a função addIssueAttachment da sessão (e não da issue) os parâmetros: id do bug, nome do arquivo, tipo do arquivo e o array de bytes do arquivo (por isso a transformação em Base64, que é como o Selenium retorna a imagem).

Essa classe foi criada para facilitar o report do bug, nada impede de criarmos outras funções com mais informações ou simplesmente colocar esse código todo no script. Isso foi feito pensando em uma maior reutilização de código... ;)

Classe ConnectMantis (Singleton)
Para que seja possível reportar o bug é necessário efetuar a conexão com o Mantis. A classe criada utiliza o Design Pattern Singleton, para que não exista várias instâncias de conexão com o Mantis, mantendo apenas uma ativa em toda a execução da aplicação.
Não é o foco explicar como funciona o Design Pattern Singleton, mas você pode clicar nos links abaixo para aprender um pouco. Vou me ater apenas a um trecho do código desta classe.

Design Pattern: http://en.wikipedia.org/wiki/Design_pattern
Singleton: http://en.wikipedia.org/wiki/Singleton_pattern

1:  public ConnectMantis() throws MalformedURLException, MCException {  
2:    URL url = new URL(MANTIS_URL);  
3:    sessao = new MCSession(url, MANTIS_USER, MANTIS_PWD);  
4:  }  

Na função acima, que está contida na classe é criado um objeto URL com a URL do Mantis que está na Interface IConstantes e na linha 3 é criado um novo objeto do tipo sessão (IMSession) passando a URL, usuário e senha do Mantis.

Interface IConstantes
A interface contém apenas constantes utilizadas em comum pela aplicação, e também para ter um ponto único de alterações de usuário e senha quando existir.

1:  public interface IConstantes {  
2:    static final String MANTIS_URL = "http://localhost/mantisbt-1.2.3/api/soap/mantisconnect.php";  
3:    static final String MANTIS_USER = "administrator";  
4:    static final String MANTIS_PWD = "root";  
5:    static final String PROJETO = "Integracao";  
6:  }  

Na linha 2 a contante é a URL de acesso aos serviços SOAP do Mantis. Tome cuidado quando você for alterar essa constante, pois você terá que colocar o seu servidor (onde aqui está como localhost) e o nome de acesso a aplicação (aqui está como mantisbt-1.2.3)
As outras contantes são o usuário na linha 3, a senha na linha 4 e o nome do projeto na linha 5.

4. Execução e modificação deste tutorial
Chegamos ao fim do tutorial. Se você deseja executar este tutorial baixe os fontes de exemplo criados no Eclipse e altere os dados de URL para o Mantis.

Se você alterar os dados da interface IConstantes o exemplo não funcionará, mas você pode usar o tutorial como base para a sua integração.
Por favor mandem sugestões e feedback's se este tutorial tem ajudado ou mesmo se estiver difícil de entender (claro que dentro de seus conhecimentos de programação Java).

4.1 Para entender mais
Você pode fazer a integração com outras linguagens de programação com o Mantis , não especificamente com o Selenium. Na verdade essa é uma implementação em Java para qualquer aplicação desenvolvida em Java, não específica para o Selenium. O que fiz foi inserir dentro do código do Selenium a integração!

Para saber mais da API Java utilizada para a comunicação com o Mantis acesse:

4.2 Fontes deste tutorial
Arquivo zipado contendo o projeto desenvolvido no Eclipse:
http://www.eliasnogueira.com/arquivos_blog/selenium/integracao/mantis/mantis-selenium-example.zip

Em breve sai o projeto com a integração em conjunto do Mantis e do Testlink!
Abraço a todos!

domingo, 3 de outubro de 2010

Integração Selenium e Testlink

Não deixe de ler o post Integração Selenium e Mantis!

Escopo
Este tutorial vai apresentar como fazer a integração do Selenium com o Testlink. Mas no que consiste essa integração?
Essa integração nada mais é do que o envio do resultado de execução do script de teste para o Testlink. Pode-se explorar muito mais do que isso, porém esse tutorial se limitará a apenas apresentar como reportar o resultado de execução do script.

Criaremos um projeto em Java com o suporte do JUnit para a criação do script de teste com o Selenium. abaixo há uma lista de itens necessários para esse tutorial.

O que é necessário?
PS: apesar de no site estar o dbfacade-testlink como em outro projeto os arquivos necessários estão no link citado acima.

1. Configurando o Testlink
Não existe uma sequencia certa de passos, eles podem ser praticamente em qualquer ordem, porém iniciarei pelo Testlink que costuma ser um ponto crítico se não configurado.
A versão que estou utilizando do Testlink é a 1.9 beta 6, porém você pode utilizar desde a versão 1.8.5

1.1 Habilitar o projeto com a Automação de Teste
Você pode ou criar um novo projeto marcando a opção Enable Test Automation (API keys) ou editando o projeto e selecionando o mesmo item.
A imagem abaixo mostra a criação de uma novo projeto



1.2 Editar o arquivo de configuração do Testlink
Depois de habilitar a automação de teste para o projeto desejado é necessário habilitar o acesso a API XML-RPC do Testlink. É esta API interna que nos possibilitará o acesso aos dados do projeto.
Você precisará alterar duas variáveis no arquivo config.inc.php do Testlink.

Adendo: o ideal é você não alterar diretamente o arquivo config.inc.php, e sim alterar o arquivo custom_config.inc.php que estará como custom_config.inc.php.example. Basta remover o ".example" e colar as variáveis que serão apresentadas abaixo no arquivo e salvá-lo.

As duas variáveis que você deve alterar são:
  • $tlCfg->api->enabled
  • $tlCfg->exec_cfg->enable_test_automation
Copie as duas linhas inteiras, cole no arquivo custom_config.inc.php e altera seus valores para:
  • $tlCfg->api->enabled = TRUE;
  • $tlCfg->exec_cfg->enable_test_automation = ENABLED;
A imagem abaixo mostra como fica o arquivo.



1.3 Gerar uma nova chave de acesso
Depois de habilitar o acesso a API XML-RPC e informar a ativação da automação no arquivo de configuração é necessário gerar a chave de acesso.
Essa chave é criada por usuário e será ela que permitirá ao Testlink identificar quem está tentando acessar os serviços XML-RPC.

Para gerar a chave vá até o menu Personal. No final da página irá existir uma seção API Interface, conforme a figura abaixo:


Clique no botão Generate a new key. Uma chave será gerada.
Procure não clicar mais vezes neste botão, pois ele irá gerar uma nova chave. Qualquer mudança na chave invalida a futura comunicação com os serviços do Testlink.
Por enquanto guarde a chave que iremos utiliza-la mais tarde dentro da API dbfacede-testlink.
A seção API interface ficará parecida com a imagem abaixo:


2. Preparando seu ambiente de Desenvolvimento
A preparação do ambiente vai apresentar somente as bibliotecas necessárias para fazer a integração funcionar. Não é intuito deste item ensinar alguma coisa sobre o Eclipse ou sobre Java.

2.1 Selecionando as bibliotecas necessárias
Para rodar o script de teste com a integração e necessário os seguintes arquivos (bibliotecas e libraries) das seguintes API's / frameworks:

  • dbfacade-testlink: necessário adicionar as seguintes bibliotecas
    • testlink-api-client-2.0.jar
    • todas as libs, exeto a junit, da pasta lib
  • Selenium RC: necessário adicionar as seguintes bibliotecas
    • selenium-server.jar
    • selenium-java-client-driver.jar
  • JUnit: necessário adicionar o JUnit 4 que já vem com o Eclipse (Add Libraries)
Abaixo segue a imagem das bibliotecas que foram adicionadas ao Eclipse.



Para adicionar cada biblioteca você precisa clicar com o botão direito no nome do projeto e selecionar Build Path/Configure Build Path...


Adicone também a biblioteca do JUnit, indo ao mesmo local (Configure Build Path...) e clicando no botão Add Library. Selecione JUnit e, em seguida, JUnit 4.

2.1 Desenvolvendo o código-fonte
A aplicação de exemplo, que está no final do post traz o código-fonte do script de teste e mais dois arquivos de código-fonte, que serão explicados abaixo.

A primeira coisa a fazer é entender o script de teste primeiro. O package, os imports e comentários em javadoc foram excluídos para exemplificar o funcionamento da classe.

1:  public class CasoTesteSelenium extends TestCase implements IConstantes {  
2:       
3:     Selenium selenium;  
4:     SeleniumServer server;  
5:       
6:     String serverHost = "localhost";  
7:     int serverPort = 4444;  
8:     String browserStartCommand = "*firefox";  
9:     String browserURL = "http://www.lojaexemplodelivros.com.br/";  
10:       
11:     public void setUp() throws Exception {  
12:        selenium = new DefaultSelenium(serverHost, serverPort, browserStartCommand, browserURL);  
13:        server = new SeleniumServer();  
14:          
15:        server.start();  
16:        selenium.start();  
17:     }  
18:       
19:     @Test  
20:     public void testPesquisaLivro() throws Exception {  
21:        String resultado = null;  
22:        String nota = null;  
23:          
24:        try {  
25:           selenium.open("/");  
26:           selenium.click("//ul[@id='nav']/li[1]/ul/li[2]/ul/li[1]/a/span");  
27:           selenium.waitForPageToLoad("30000");  
28:             
29:           assertEquals("3 Item(s)", selenium.getText("//div[@id='main']/table[1]/tbody/tr/td[1]/strong"));  
30:           assertEquals("[PRODUTO DE EXEMPLO] - Use a Cabeça! Java", selenium.getText("link=[PRODUTO DE EXEMPLO] - Use a Cabeça! Java"));  
31:           assertEquals("[PRODUTO DE EXEMPLO] - Entendendo e Dominando o Java: para Internet", selenium.getText("link=[PRODUTO DE EXEMPLO] - Entendendo e Dominando o Java: para Internet"));  
32:           assertEquals("[PRODUTO DE EXEMPLO] - Ajax com Java", selenium.getText("link=[PRODUTO DE EXEMPLO] - Ajax com Java"));  
33:             
34:           selenium.click("//img[@alt='[PRODUTO DE EXEMPLO] - Ajax com Java']");  
35:           selenium.waitForPageToLoad("30000");  
36:           assertTrue(selenium.isTextPresent("2x R$ 222,25 sem juros"));  
37:           assertTrue(selenium.isTextPresent("3x R$ 148,17 sem juros"));  
38:           assertTrue(selenium.isTextPresent("4x R$ 111,13 sem juros"));  
39:           assertTrue(selenium.isTextPresent("5x R$ 88,90 sem juros"));  
40:          
41:        resultado = TestLinkAPIResults.TEST_PASSED;  
42:          
43:        } catch (Exception e) {  
44:           resultado = TestLinkAPIResults.TEST_FAILED;  
45:           nota = e.getMessage();  
46:           e.printStackTrace();  
47:        } finally {  
48:           ResultadoExecucao.reportTestCaseResult(PROJETO, PLANO, CASO_TESTE1, BUILD, nota, resultado);  
49:        }  
50:     }  
51:       
52:     public void tearDown() throws Exception {  
53:        selenium.stop();  
54:        server.stop();  
55:     }  
56:  }  
57:    

Basicamente há a criação dos atributos do Selenium e SeleniumServer para a execução, os métodos setup() e tearDown() do JUnit e o caso de teste automatizado.
Note que o bloco do caso de teste (método testPesquisaLivro) está com um try-catch. Isso é necessário para que possamos enviar a informação ao Testlink se o script falhou ou passou.

Na linha 41 há o seguinte código:
resultado = TestLinkAPIResults.TEST_PASSED;

Este atributo (resultado) é uma String que armazena o status de execução. Neste caso ele está no final dos passos do script passando sucesso (TestLinkAPIResults.TEST_PASSED).
É ele que vai dizer para o Teslink que o script passou!

Dentro do bloco de catch (linhas 44 a 46) há os comandos que serão executados quando o script falhar por algum motivo. Note que na linha 44 passamos para a variável de resultado a informação TestLinkAPIResults.TEST_FAILED.
Ele é que vai dizer para o Testlink que o script falhou!

Na linha 45 a mensagem de erro gerado pelo script vai para a variável nota, para que seja adicionado a mensagem de erro no campo Nota do Testlink.

Na linha 48, dentro do bloco de finally há o envio de resultado da execução do teste para o Testlink.
É ele que envia os dados para o Testlink!

Há um método é chamado (reportTestCaseResult) para passar as informações do Selenium para o Testlink.

Classe ResultadoExecucao
Dentro do projeto no pacote com.blogspot.sembugs há a classe ResultadoExecucao, que é a responsável por enviar o resultado do script ao Testlink. Eu gerei essa classe como chamada de uma função da API dbfacade-testlink.

PS: package, imports e comentários em javadoc foram excluídos para exemplificar o funcionamento da classe.

1:  public class ResultadoExecucao implements IConstantes {  
2:    
3:    public static void reportTestCaseResult(String projetoTeste, String planoTeste, String casoTeste, String nomeBuild, String nota, String resultado) throws TestLinkAPIException {  
4:        
5:      // Cria uma instância do TestLinkAPIClient para comunicação com o Testlink  
6:      TestLinkAPIClient testlinkAPIClient = new TestLinkAPIClient(DEVKEY, URL);  
7:      // Submete os resultados para o Testlink  
8:      testlinkAPIClient.reportTestCaseResult(projetoTeste, planoTeste, casoTeste, nomeBuild, nota, resultado);  
9:    
10:    }  
11:  }  

Na linha 6 há a criação de uma instância da classe TestlinkAPIClient, passando a URL do XML-RPC do Testlink (URL) e a chave do usuário (DEVKEY).

Muito atenção!
A URL do XML-RPC é http://servidor/nome_testlink/lib/api/xmlrpc.php, onde:
  • servidor: é o nome do servidor onde está instalado o Testlink. Ex: localhost
  • nome_testlink: é o nome de acesso a aplicação do testlink. Ex: testlink
A DEVKEY foi gerada lá nos primeiros passos deste post dentro do Testlink.
Você deve alterar a DEVKEY para o seu usuário e alterar o servidor e nome_testlink para as suas configurações quando for rodar o exemplo.

A linha 8 envia os dados para o Testlink, com alguns dados como parâmetro, que são:
  • projetoTeste: nome do projeto de teste que estamos usando no Testlink
  • planoTeste: nome do plano de teste que estamos usando no Testlink
  • casoTeste: nome do caso de teste que estamos usando no Testlink
  • nomeBuild: nome da build que estamos usando no Testlink
  • nota: nota que será inserida na execução quando houver falha na execução do script
  • resultado: resultado passado pelo script
Interface iConstantes
Foi criado uma interface com os dados necessários para o envio dos dados para o Testlink, que são os parâmetros que foram descritos acima.

1:  public interface IConstantes {  
2:    
3:     final String DEVKEY = "84947019532f2f23e1d90b6de748cd66";  
4:     final String URL = "http://www.eliasnogueira.info/arquivos_blog/testlink_1_9_beta6/lib/api/xmlrpc.php";  
5:     final String PROJETO = "Integracao Selenium e Testlink";  
6:     final String PLANO = "PT001 - Integracao Selenium e Testlink";  
7:     final String BUILD = "Ciclo 1";  
8:     final String CASO_TESTE1 = "Pesquisar no blog";  
9:       
10:  }  

Note que todos os dados que estão contidos no meu Testlink estão ali. Você vai precisar alterar estes dados para fazer os seus testes.
Todas as informações que precisam ser enviadas para o Testlink através do método reportTestCaseResult da classe ResultadoExecucao estão nesta interface.

3. Criação do(s) Casos de Teste
Por incrível que pareça você não precisa colocar o caso de teste com o tipo "Automatizado" e nem os passos como "Automatizado" para que o script insira o resultado de execução do caso de teste automaticamente, eles servem apenas para informação.
Abaixo segue a imagem deste item dentro do caso de teste citadas.



4. Execução e modificação deste tutorial
Chegamos ao fim do tutorial. Se você deseja executar este tutorial baixe os fontes de exemplo criados no Eclipse e altere a URL de conexão com o Testlink.

Se você alterar os dados da interface IConstantes o exemplo não funcionará, mas você pode usar o tutorial como base para a sua integração.

Por favor mandem sugestões e feedback's se este tutorial tem ajudado ou mesmo se estiver difícil de entender (claro que dentro de seus conhecimentos de programação Java).

4.1 Para entender mais
Você pode fazer a integração com outras linguagens de programação com o Testlink, não especificamente com o Selenium. Na verdade essa é uma implementação em Java para qualquer aplicação desenvolvida em Java, não específica para o Selenium. O que fiz foi inserir dentro do código do Selenium a integração!

Acesse as seguintes páginas para ter mais informações sobre os serviços XML-RPC do Testlink:

4.2 Fontes deste tutorial
Arquivo zipado contendo o projeto desenvolvido no Eclipse:
http://www.eliasnogueira.com/arquivos_blog/selenium/integracao/testlink/testlink-selenium-example.zip

Abraço a todos!