: : www.mundoj.com.br : : Qualidade através de testes funcionais com Selenium, JBehave, Maven e Integração Contínua Entenda as vantagens de desenvolver software com foco em qualidade e aprenda através de um exemplo prático a configurar e utilizar em conjunto as ferramentas JBehave, Selenium e Maven com objetivo de um constante acompanhamento da qualidade através da integração contínua. Eder Ignatowicz ([email protected]): Doutorando em Engenharia Elétrica na Unicamp, mestre em Engenharia Elétrica pela Unicamp (2009) e graduado em Ciência da Computação pela Universidade Estadual de Londrina (2007).Trabalha com java há mais de 3 anos e atualmente é engenheiro de Software na Dextra. Também leciona diversos cursos de graduação e pós-graduação na Faccamp e Unisal. Rafael Farias Silva ([email protected]): É formado em Análise de Sistemas pela PUC Campinas em 2007. Trabalha com java há 4 anos, e possui a certificação SCEA 5. É o idealizador e principal desenvolvedor do projeto opensource Jsigner (http://code.google.com/p/jsigner/), que automatiza engenharia reversa de classes através do maven. Já participou de projetos de diversos tamanhos em várias áreas, tais como telecom, bancária, saúde etc. Atualmente é arquiteto de software na empresa NCI Soluções em Saúde. 44 Garantir a qualidade de Software tem sido um desafio prioritário nos projetos de TI. Quer seja no desenvolvimento, integração, implementação ou customização de software, o aprimoramento da qualidade é considerado uma questão primordial para toda comunidade de desenvolvimento. Testes automatizados são praticamente mandatórios para que a comunidade open-source confie e adote novos frameworks desenvolvidos. Nas últimas décadas, a pesquisa em engenharia de software tem desenvolvido normas, metodologias e técnicas para medição e garantia da qualidade de software. Grande parte destes estudos baseiase na avaliação de qualidade interna e externa de um software. Mas o que é qualidade de software? Como garantir a qualidade de um software da maneira mais eficiente possível? Visando maximizar a qualidade de um software da maneira mais eficiente possível, este artigo tem como objetivo propor uma maneira de garantir qualidade externa através de testes automatizados com BDD utilizando ferramentas como Selenium, JBehave, Maven2 e o plugin Cargo. radativamente, a garantia da qualidade do software torna-se um tópico de extrema importância no desenvolvimento de sistemas, pois as organizações estão em busca de vantagens competitivas e têm investido em automatizar seus processos de negócio. Tais processos mudam em um ritmo acelerado e consequentemente os softwares que suportam esses processos devem enquadrar-se a essas mudanças no menor prazo possível para garantir a satisfação dos clientes. Um meio de conquistarmos a agilidade necessária para atendermos rapidamente tais mudanças é desenvolver um software de qualidade, empregando técnicas para controle de entropia e garantia de funcionamento. Desta forma, a equipe cria segurança para manter a evolução do sistema em um ritmo sustentável como é pregado pelas metodologias ágeis. Mas como atingir tal objetivo sem causar impactos no sucesso do projeto? Como maximizar a qualidade sem comprometer o custo ou o prazo? Há como evoluirmos o software de maneira segura sem atentar para qualidade? Com objetivo de discutir estas questões e propor uma forma de garantir a qualidade externa através de testes automatizados com BDD, este artigo está organizado da seguinte forma: na primeira seção são discutidos conceitos referentes ao triângulo da qualidade e como as metodologias de desenvolvimento se relacionam com a qualidade de software. Em seguida, são descritas as diferenças entre qualidade externa e qualidade interna de um software através de um exemplo prático utilizando JBehave, Selenium, Maven2 e Cargo. Baseado neste exemplo são discutidas questões como manutenibilidade de testes e diferentes estratégias para realização de testes funcionais. Na última seção, são apresentadas as considerações finais, finalizando o presente artigo. Triângulo da qualidade O desenvolvimento de software é um processo complexo que exige um esforço colaborativo de diversos desenvolvedores trabalhando por um longo período de tempo. O produto final dificilmente será compreendido por uma única pessoa. Não importa quão boa seja a documentação, metodologia, plano de desenvolvimento etc., um projeto só será bem-sucedido se encontrarmos o equilíbrio entre as variáveis que guiam o desenvolvimento de software. Mas que variáveis são estas? O Triângulo da Qualidade (figura 1), também conhecido como triângulo do escopo, é uma das formas de listar os trade-offs relacionados ao desenvolvimento de software. ângulo (alta qualidade em um baixo tempo de desenvolvimento, por exemplo), mas irá comprometer duramente a outra variável (irá aumentar o custo do projeto). TIME COST QUALITY Figura 1. Triângulo da qualidade. Relação entre metodologias e a qualidade de software As metodologias atuais lidam de formas diferentes com as variáveis do Triângulo da Qualidade. Mas de que maneira isto afeta o desenvolvimento de software? Metodologias “não-ágeis” As metodologias “não-ágeis” trabalham com escopo e prazo fixo e desta forma o único fator que pode variar é a qualidade. A longo prazo, esta não é uma boa estratégia, pois se não nos atentamos para a qualidade o software tende a “apodrecer”. A correria para entregar o projeto dentro do prazo e com o escopo definido nas primeiras fases de desenvolvimento fatalmente acaba forçando as equipes a não dar a devida importância para os fatores que aumentam a manutenibilidade do software, tais como testes automatizados. Mesmo que a equipe consiga atender seus objetivos primários (entregar o sistema no prazo e escopo), se nada mudar, o futuro deste sistema estará comprometido. A manutenibilidade de um software trata em responder quão fácil é a manutenção ou aperfeiçoamento de um software. Esta modificação pode ser a correção de um bug, aumento de performance ou a criação de uma nova funcionalidade. Com o software entrando em produção depois de um longo período de desenvolvimento, a tendência é que ocorram muitas solicitações de mudança e este é o momento em que a equipe precisará demonstrar uma maior agilidade. A falta de manutenibilidade do sistema desenvolvido prejudicará os resultados, pois, desta forma, o custo de alterações no software tende a aumentar cada vez mais, o que acabará o condenando a substituição. Um trade-off é uma situação em que obrigatoriamente você deverá escolher uma opção em detrimento da outra. Este princípio baseia-se no fato de que dada a ênfase em um elemento, uma menor atenção é dada aos outros elementos. No nosso caso, Custo, Prazo e Qualidade são os três fatores que podemos focar nossa atenção no desenvolvimento de software. Estes fatores formam os três lados deste triângulo. Por exemplo, é difícil aumentar a qualidade sem aumentar o custo, cronograma ou ambos para o software em desenvolvimento. É possível alcançarmos alta prioridade em dois elementos do tri45 : : www.mundoj.com.br : : Metodologias “ágeis” Como alcançar a qualidade externa A principal diferença estratégica entre as metodologias tradicionais e as metodologias ágeis é que a agilidade prega que a qualidade deve ser constante. Devemos progredir em um ritmo sustentável, em que a qualidade é fixa e o que varia fica a critério do cliente. Pode ser o prazo ou o escopo. Como profissionais, nós não aceitamos fazer algo sem garantia de qualidade, afinal quem paga o preço por isso é a equipe e o cliente. A qualidade externa é tangível através de testes de aceitação. Este tipo de teste, também conhecido como teste de caixa preta, é considerado por muitos autores como a atividade de teste que precede uma implantação final do sistema. Contudo, em metodologias ágeis, este teste pode ser utilizado com objetivo de garantir que cada user story entregue atenda os requisitos esperados pelos nossos clientes. Com a qualidade constante, podemos garantir que o software poderá ficar em produção o tempo que o cliente desejar, com modificações constantes, em um ritmo sustentável, previsível e sem aumento de custo para novas funcionalidades a longo prazo. A princípio, o investimento em qualidade/testes automatizados pode parecer grande e desnecessário, mas este investimento é recompensado ao longo do projeto. Ao analisar essa questão, é preciso levar em consideração o custo de garantir o funcionamento do sistema manualmente a cada modificação para avaliar os benefícios da automação. Uma vez que foi investido o tempo necessário para codificação do teste, ele pode ser executado infinitamente, enquanto que o fato da não existência do teste força a equipe a retestar manualmente partes do sistema a cada alteração. Devemos ter em mente que o projeto não se encerra quando o sistema entra em produção. Este marco é apenas o início do ciclo de vida do software implantado em nossos clientes. Qualidade externa VS Qualidade interna Segundo o livro “Growing object oriented software, guided by tests”, qualidade externa é o quão bem o sistema atende a necessidade de seus clientes e usuários (o sistema é funcional, confiável, responsivo etc.). Por outro lado, a qualidade interna é o quão bem o sistema atende as necessidades da equipe (é fácil de modificar, entender, administrar etc.). Desta forma, a definição destes testes é importante para identificar junto ao cliente o que é esperado (e realmente importante) para cada user story do sistema. Após a definição, a equipe deve implementar os cenários levantados na forma de testes na camada mais externa da aplicação, que na maioria dos casos é a interface gráfica. Desta maneira, o sistema terá testes de aceitação automatizados, que demonstrarão o impacto de modificações e adições de novas funcionalidades nas histórias que já estavam implementadas. Como alcançar a qualidade interna É possível estabelecer uma relação direta entre manutenibilidade e qualidade interna. Neste quesito são avaliados pontos como tamanho de métodos, tamanho de classes, complexidade ciclomática, dependência entre pacotes etc. Para acompanhar estes fatores, existem ferramentas como o Sonar (“Evoluindo Design e Arquitetura Através das Métricas do Sonar” – MundoJ edição 43). Uma boa maneira de garantir a qualidade interna é por meio de testes unitários construídos através de TDD (Test Driven Development). Esta abordagem é utilizada com o intuito de escrever somente o código necessário para que os testes passem. É importante utilizar TDD para assegurar a qualidade interna, pois desenvolver o código de produção do ponto de vista do código cliente orienta as decisões de design, tornando o sistema mais coeso e menos acoplado. A figura 2, extraída do livro “Growing object oriented software, guided by tests”, exemplifica a relação entre os tipos de teste e qual o tipo de qualidade assegurada. 'JHVSB5JQPEFUFTUF95JQPEFRVBMJEBEF Exemplo prático Visando a maximização da eficiência da realização de testes, a seguir mostraremos um exemplo de teste de aceitação de uma user story utilizando as ferramentas JBehave, Selenium, Maven criando desta forma um exemplo passível de execução em um 46 ambiente de integração contínua. Este exemplo está disponível para download no site da revista MundoJ. JBehave JBehave é um framework java de Behaviour Driven Development. O uso do framework é bastante simples e a sua ideia principal é escrever em um arquivo-texto a user story e seus cenários. O JBehave executa linha a linha do arquivo-texto, relacionando-a a um método Java que é a materialização em código do objetivo de negócio da respectiva linha textual. Configurando o ambiente O código-fonte deste exemplo encontra-se disponível para download com um guia para configuração de todos aspectos necessários para a sua execução. Iremos focar no código-fonte para não poluir o artigo com detalhes de configuração. Iniciaremos pelo código do JBehave e do Selenium. Para que as duas ferramentas funcionem integradas, é necessário criar uma superclasse para os testes funcionais. Observe a Listagem 2. Selenium O Selenium é uma ferramenta criada para execução de testes funcionais de aplicações web. Ele funciona para diversos browsers (IE, Firefox, Chrome etc.), e possui uma API capaz de abrir um browser e reproduzir todas as ações que uma pessoa executaria no uso real da aplicação. No nosso exemplo, utilizaremos a versão 1.0 do Selenium, pois a versão 2.0 ainda está em fase beta. Listagem 2. Classe Base dos Testes Funcionais public abstract class TesteFuncional extends ConfigurableEmbedder { private List<String> estorias = new ArrayList<String>(); protected static Selenium selenium = criarSelenium(); private SeleniumContext seleniumContext = new SeleniumContext(); private ConditionRunner conditionRunner = SeleniumConfiguration .defaultConditionRunner(selenium); A integração entre o Selenium e o Jbehave é bastante interessante, pois é possível visualizar as histórias sendo executadas passo a passo junto com a sua descrição textual. O browser abre e exibe no canto superior esquerdo o passo da história que está sendo executado e em seguida é possível visualizar o Selenium manipulando o browser para executar o passo que está sendo exibido. private static Selenium criarSelenium() { selenium = new DefaultSelenium(“localhost”, 8888, “*firefox”, “http://localhost:8088/exemplo/”); selenium.start(); selenium.setSpeed(“1000”); return selenium; } public TesteFuncional() { useConfiguration(new SeleniumTestConfiguration(selenium, seleniumContext)); } Maven/Cargo plugin O Maven é uma ferramenta de build e suporte ao ciclo de vida do software já consolidada no mercado. Vamos focar no plugin cargo, que é capaz de iniciar diversos servidores, tais como Jboss, Jetty, Tomcat etc. É possível configurar este plugin para iniciar o servidor antes dos testes funcionais, executar os testes e desligar o servidor. No exemplo prático iremos mostrar a configuração deste plugin. /** * @param caminhoCompletoDaEstoria -> caminho para a estoria a partir * do classpath. Exemplo: br/com/mundoJ/incluir_usuario.story **/ public void adicionarEstoria(String caminhoCompletoDaEstoria) { this.estorias.add(caminhoCompletoDaEstoria); } Caso de uso A seguir iremos desenvolver um exemplo simples que demonstra a configuração e o funcionamento das tecnologias sugeridas em conjunto. public void adicionarPassos(Object passos) { super.addSteps(new Steps(configuration(), passos)); } Para essa demonstração iremos nos basear em uma história de usuário simples conforme a seguir: @Test public void run() throws Throwable { Embedder embedder = configuredEmbedder(); embedder.runStoriesAsPaths(estorias); } Listagem 1. História de exemplo. } Narrativa: Como um administrador do sistema Desejo incluir usuários Para possibilitar que outras pessoas acessem o sistema Cenário: tentar incluir usuário com login já existente Dado que já existe usuário com nome Adam Smith e login asmith Quando administrador tenta incluir novo usuário com nome Amanda Smith e login asmith Então o usuário não é incluído, pois já existe outro usuário com o mesmo login A classe base da Listagem 2 herda org.jbehave.core.ConfigurableEmbedder para que os testes sejam executados pelo JBehave. Ela possui métodos para adicionar histórias, que são arquivos-texto com a extensão .story e devem ser mantidos no classpath da aplicação. A criação do client do selenium também está mantida nesta classe, pois para configurar o JBehave é necessário passar uma instância de org.jbehave.core.configuration.Configuration e, neste exemplo, herdamos esta classe criando a SeleniumTestConfiguration, como é possível acompanhar na Listagem 3. 47 : : www.mundoj.com.br : : Listagem 3. Exemplo de Configuração do Selenium. public class SeleniumTestConfiguration extends SeleniumConfiguration { public SeleniumTestConfiguration(Selenium selenium, SeleniumContext seleniumContext) { super(); doDryRun(false); useStoryLoader(new LoadFromClasspath(this.getClass().getClassLoader())); usePendingStepStrategy(new PendingStepStrategy() { Desta forma, o Junit é capaz de executar esta classe como um teste unitário, pois a superclasse já possui um método anotado com @Test, que executa as histórias adicionadas. Portanto para cada nova história, será criado uma nova classe de teste que apenas adiciona a história que será executada e as classes de passos, que é onde o JBehave irá procurar os métodos que devem ser executados. Neste cenário, vamos verificar a implementação dos passos na classe ManterUsuariosPassos (Listagem 5). Listagem 4. Implementação da história. public class ManterUsuariosPassos { public void handleFailure(Throwable throwable) throws Throwable { Assert.fail(“Passo ‘” + throwable.getMessage() + “’ nao definido!.”); } private Selenium selenium; public ManterUsuariosPassos() { super(); this.selenium = TesteFuncional.selenium; } }); useKeywords(new LocalizedKeywords(new Locale(“PT_br”), “jbehave-keywords”, SeleniumTestConfiguration.class.getClassLoader())); @Given(“ja existe usuario com nome $nome e login $login”) public void existeUsuarioComNomeELogin(String nome, String login) { //... (codigo omitido) } useStoryParser(new RegexStoryParser(keywords())); useFailureStrategy(new RethrowingFailure()); useDefaultStoryReporter(new ConsoleOutput()); useStepCollector(new MarkUnmatchedStepsAsPending()); useStepFinder(new StepFinder()); useStepPatternParser(new RegexPrefixCapturingPatternParser()); useStepMonitor(new SilentStepMonitor()); useStepdocReporter(new PrintStreamStepdocReporter()); @When(“administrador tenta incluir novo usuario com nome $nome e login $login”) public void incluirNovoUsuario(String nome, String login) { selenium.open(“novoUsuario.jsp”); selenium.waitForPageToLoad(“20000”); useSelenium(selenium); useSeleniumContext(seleniumContext); useStepMonitor(new SeleniumStepMonitor(selenium, seleniumContext, new SilentStepMonitor())); //verifica se esta na pagina correta Assert.assertEquals(“Novo usuario”, selenium.getText(“div#header h1”)); selenium.type(“nome”, nome); selenium.type(“login”, login); selenium.click(“div.buttons input#adicionar”); } } } Com essa configuração é possível executar o cenário da Listagem 1 como um teste funcional. Neste ponto podemos identificar o papel do JBehave. Ele executa cenários escritos em qualquer idioma, bastando provermos no classpath um arquivo de tradução, no caso deste exemplo o jbehave-keywords.properties, para traduzir as palavras-chave do BDD, tais como Given, When, Then, Scenario, Narrative, entre outras. Agora que já temos a infraestrutura pronta, podemos desenvolver a nossa classe de testes (Listagem 4). public class CadastroDeUsuariosTesteFuncional extends TesteFuncional { public CadastroDeUsuariosTesteFuncional() { adicionarPassos(new ManterUsuariosPassos()); adicionarEstoria(“br/com/mundoj/exemplo/incluir_usuario.story”); } } 48 @Then(“usuario nao eh incluido pois ja existe outro usuario com o mesmo login”) public void verificarLoginDuplicado() { String mensagens = selenium.getText(“ul.messages”); Assert.assertTrue(mensagens.contains(“login duplicado”)); } } 'JHVSB&YFDVÎÍPEPUFTUF Através desta classe podemos visualizar (figura 3) como o JBehave funciona. Para cada linha do arquivo .story, ele busca nas classes de passos uma anotação com valor que corresponda ao texto da linha sendo executada. Podemos observar que os métodos desta classe utilizaram o Selenium para manipular o browser. A API do framework é bem simples e dispensa explicações sobre o código. Ele é capaz de identificar os elementos do html de diversas formas, tais como id, seletores css, e xpath, e executar as mesma ações que um usuário humano, tais como clicar, digitar, apertar teclas de atalho, realizar drag and drop etc. Manutenibilidade de testes Ao adotarmos uma solução de testes funcionais baseados na interface gráfica devemos nos atentar para a manutenibilidade dos testes. O código de testes, assim como o código de produção, deve ser bem projetado visando a facilidade na evolução do sistema. Pelo fato dos testes de aplicações web se basearem na estrutura do html, que pode mudar com frequência, é preciso tomar alguns cuidados, pois uma mudança em uma única tela pode fazer diversos testes falharem. Como mudanças na interface gráfica são frequentes, devemos nos preparar para que a correção dos testes que falharam sejam em um único ponto, facilitando a manutenção dos testes conforme o sistema evolui. Uma alternativa para atingir este objetivo é utilizar o Design Pattern Page Objects1. Basicamente, a ideia deste pattern é criar uma classe para representar cada tela do sistema. O papel deste pattern é encapsular os detalhes da estrutura interna da interface gráfica (html, css, js), fornecendo para diversas classes de teste uma API única por tela. A utilização deste pattern facilita a modificação do sistema, pois ao modificarmos um html do sistema existe apenas um ponto de manutenção nos testes, o respectivo Page Object que representa a tela modificada. Este design possibilita o crescimento do sistema coberto por testes funcionais de forma sustentável. 1 http://code.google.com/p/selenium/wiki/PageObjects 49 : : www.mundoj.com.br : : Estratégias para testes funcionais Quando definimos a arquitetura para os testes funcionais, devemos nos atentar a um ponto muito importante: a preparação do contexto onde o teste será executado. Uma possível abordagem para construção do contexto é garantir a ordem de execução dos testes, para que, por exemplo, o teste da consulta de usuário seja executado após o teste da inclusão. Dessa forma, quando o teste da consulta for executado pode-se assumir que o usuário do teste da inclusão já existirá. Outra abordagem possível é garantir que cada teste saiba preparar o contexto necessário para a sua execução. Os fatores que devem ser levados em consideração para tomar a decisão de qual abordagem seguir são: t 7FMPDJEBEFEFGFFECBDL2VBOUPUFNQPMFWBQSBFYFDVUBSVN teste isolado?) t .BOVUFOJCJMJEBEF.VEBOÎBTFNVNUFTUFQPEFNBGFUBSPVtros testes?) t 1SFDJTÍP EP GFFECBDL 2VBOEP VN UFTUF GBMIB FV TFJ FYBUBmente o que não está funcionando?) t 3FMBÎÍPDVTUPWTCFOFGÓDJP Analisando estes fatores, a abordagem onde cada teste sabe preparar o contexto para a sua execução pode ser mais trabalhosa no começo, pois a infraestrutura para configuração do contexto pode não ser simples (JDBC direto para criação dos dados necessários?, ejbs remotos?). Porém este custo inicial certamente será compensado, pois o desenvolvedor ganha uma ferramenta poderosa no ciclo de vida de desenvolvimento: o feedback eficiente. Utilizando esta abordagem, é possível que um único teste funcional seja executado diversas vezes, com um tempo de execução aceitável. Este rápido feedback gera confiança na equipe para modificar o projeto e executar refactorings. Finalmente, para que seja possível executar os testes, devemos iniciar o selenium-server. Este componente é responsável pela manipulação do browser. É importante saber que é possível iniciar o selenium-server programaticamente no código do nosso teste, porém neste exemplo optamos por deixar o maven inicializar o servidor antes dos testes de integração e encerrá-lo após a execução do último teste, pois desta forma o selenium-server é iniciado apenas uma vez, o que economiza tempo de execução dos testes. Esta abordagem possui um trade off, pois embora deixar o maven responsável por inicializar o servidor diminui consideravelmente o tempo de execução da suíte de testes funcionais, para execução dos testes através de uma IDE é necessário inicializar o seleniumserver manualmente. Felizmente é possível inicializar o server manualmente através do maven, executando o comando mvn selenium:start-server. Após a execução deste comando, é possível executar qualquer teste de maneira desacoplada do ciclo de vida do maven. A configuração da Listagem 5 inicializa o selenium server na fase pre-integration-test e finaliza na etapa post-integration-test. Para entender como funciona o ciclo de vida do maven, consulte o link http://maven.apache.org/guides/introduction/introductionto-the-lifecycle.html Com essa configuração o projeto está pronto para ser executado em qualquer ferramenta de integração contínua. A única ressalva é que como o teste depende do browser, o servidor de integração contínua deve possuir uma interface gráfica instalada. Essa limitação pode ser um empecilho, pois nem sempre temos controle sobre o ambiente onde nossa integração contínua será executada. Para contornar este problema, existe a ferramenta “xvfb2”, que 1 50 IUUQXXXYGSFFPSH9WGCIUNM Listagem 5. Configuração Maven Selenium Server. <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>selenium-maven-plugin</artifactId> <version>1.0.1</version> <executions> <execution> <id>start-selenium</id> <phase>pre-integration-test</phase> <goals> <goal>start-server</goal> </goals> <configuration> <background>true</background> <port>8888</port> <singleWindow>true</singleWindow> <timeoutInSeconds>60</timeoutInSeconds> </configuration> </execution> <execution> <id>stop-selenium</id> <phase>post-integration-test</phase> <goals> <goal>stop-server</goal> </goals> <configuration> <background>true</background> <port>8888</port> </configuration> </execution> </executions> </plugin> funciona exatamente como uma interface gráfica, porém com toda a execução em memória, sem exibir nenhuma saída na tela. Desta forma é possível executar os seus testes em um browser sem a utilização de uma interface gráfica. Outra importante vantagem do xvfb é que este lida com diferentes resoluções gráficas, expandindo a nossa possibilidade de testes do nosso sistema. Listagem 6. Configuração XVFB Maven. <execution> <id>xvfb</id> <phase>pre-integration-test</phase> <goals> <goal>xvfb</goal> </goals> </execution> Para Saber Mais “Evoluindo Design e Arquitetura Através das Métricas do Sonar” – MundoJ edição 43. Considerações finais Conforme visto neste artigo, garantir a qualidade do software é um dos principais desafios no nosso dia-a-dia. Inevitavelmente softwares evoluem e a melhor e mais eficiente forma de administrar este crescimento é através da utilização de testes automatizados. Contudo esta automatização é muitas vezes custosa e o retorno do investimento da automatização não é imediato. Automatizar e gerenciar os testes da forma mais eficiente possível é a resposta ao trade-off gerado pela verificação da qualidade do software e consequente aumento da qualidade do produto desenvolvido. Esperamos com este artigo ter demonstrado uma solução para criar, manter e avaliar a qualidade externa de um software e que tenhamos esclarecido a importância da garantia da qualidade no EJBBEJBEPEFTFOWPMWFEPSQSPmTTJPOBMEFTPGUXBSFt Para utilizar o xvfb nos testes funcionais, basta ter o software instalado no sistema operacional, e configurar o plugin seleniummaven-plugin para a inicialização da ferramenta. A Listagem 6 demonstra a configuração de mais um <execution>, que pode ser adicionado à Listagem 6 para a inicialização do servidor xvfb. GUJ – Discussões sobre o tema do artigo e assuntos relacionados Discuta este artigo com 100 mil outros desenvolvedores em www.guj.com.br/MundoJ Referências t t (SPXJOH0CKFDU0SJFOUFE4PGUXBSFHVJEFECZUFTUTQPS4UFWF'SFFNBOBOE/BU Pryce 5IF1SBHNBUJD1SPHSBNNFS'SPN+PVSOFZNBOUP.BTUFSQPS"OESFX)VOUBOE David Thomas. 51