Tentei escrever testes de unidade de interface do usuário para meus aplicativos de GUI e enfrento o problema de que, embora funcionem bem quando os escrevo inicialmente, eles se tornam quebradiços e quebram sempre que o design é alterado (ou seja, com frequência). Estou lutando para encontrar um conjunto de diretrizes que me levem a realizar testes de unidade sustentável para a GUI.
Por enquanto, uma coisa que eu descobri é que os testes dizendo "esse componente deve mostrar seus dados de entrada em algum lugar" são bons (e isso é muito fácil com o HTML). Testes que verificam um estado específico de uma parte específica do componente geralmente são frágeis. Testes como click-click-click-expect, que tentam seguir o comportamento do usuário e a lógica comercial subjacente (que é a parte mais importante) geralmente acabam quebradiços. Como escrevo bons testes?
Para ser mais preciso, eu gostaria de conhecer alguns padrões sobre o que eu poderia testar na minha interface do usuário, não exatamente como testá-lo. Convenções de nomenclatura e identificadores fixos são bons, mas não resolvem o problema principal, ou seja, as GUIs mudam muito. Eu gostaria de testar os comportamentos que provavelmente não mudarão. Como encontrar a coisa certa para testar?
Respostas:
Um problema comum com os testes da GUI ... A principal razão pela qual esses testes são considerados frágeis é porque eles não podem sobreviver a uma mudança na GUI que não é uma alteração nos requisitos . Você deve estruturar seu código de teste de forma que uma alteração na GUI seja isolada em um único local nos testes.
Como exemplo, considere um teste com a seguinte redação:
Aqui há bastante espaço para que esse teste seja interrompido quando você refaz a interface, mesmo que o requisito para a validação permaneça.
Agora, vamos colocar isso em um pequeno texto alternativo:
O teste é o mesmo, os requisitos são os mesmos, mas esse tipo de teste sobreviverá a uma reforma na sua interface do usuário. Você precisará alterar o código, obviamente, mas o código será isolado. Mesmo que você tenha dez ou vinte testes para a sua página de perfil e mova sua lógica de validação que exibe mensagens de erro de alertas javascript para jquery-pop-ups, por exemplo, você só precisa alterar a parte do teste que verifica as mensagens de erro.
fonte
Esse é um problema comum. Eu prestaria atenção a:
Como você nomeia elementos
Use css id ou classe para identificar elementos. Favor usar o ID do CSS quando o objeto for único. Considere a estrutura que você está usando, por exemplo, com o Ruby on Rails, o
name
atributo é atribuído automaticamente e pode (não intuitivamente) ser melhor do que usar o id ou classe cssComo você identifica elementos.
Evite identificadores posicionais como
table/tr/td/td
em favor de formas comotd[id="main_vehicle"
outd[class='alternates']
. Considere usar atributos de dados quando apropriado. Ainda melhor, tente evitar as tags de layout, como<td>
as anteriores, para adicionar um span e usá-lo, por exemplo,<span id="main_vehicle">
ou um seletor de curinga, como*[id="main_vehicle"]
onde*
agora pode ser um div, span, td, etc.Usando atributos de dados específicos de teste que são usados apenas para qa e teste.
Evite qualificação desnecessária para elementos. Você pode encontrar o seguinte:
body.main div#vehicles > form#vehicle input#primary_vehicle_name
No entanto, isso exige que o campo de entrada permaneça em um formulário com um ID exato do veículo e em uma página com uma carroceria que possua uma classe de main e uma div com um ID de veículos que tenha um filho imediato de um formulário com um ID de veículo. Qualquer alteração em qualquer estrutura e o teste é interrompido. Nesse caso, você pode achar que
input#primary_vehicle_name
é suficiente para identificar exclusivamente o elemento.
Evite testes que se refiram ao texto visível. O texto na página que é mostrado ao usuário geralmente muda com o tempo, à medida que o site é mantido e atualizado; portanto, use identificadores como id css e classe css ou atributos de dados. Elementos como
form
,input
eselect
usados em formulários, também são boas partes dos elementos de identificação, geralmente em combinação com ID ou classe, por exemplo,li.vehicle
ouinput#first-vehicle
Você também pode adicionar seus próprios identificadores, por exemplo<div data-vehicle='dodge'>
. Dessa forma, você pode evitar o uso de IDs ou classes de elementos, que provavelmente serão alterados por desenvolvedores e designers. Na verdade, descobri com o tempo que é melhor trabalhar apenas com desenvolvedores e designers e chegar a um acordo sobre nomes e escopos. É difícil.Como os dados fixos são mantidos.
Semelhante à identificação de elementos reais, tente evitar o seletor codificado em linha, identificando valores em favor dos objetos de página - pequenos pedaços de texto que são mantidos em variáveis ou métodos e, portanto, podem ser reutilizados e também mantidos centralmente. Exemplos de variáveis javascript seguindo este padrão para valores codificados:
Mais informações sobre objetos de página no selenium wiki e selenium docs
Comunicação com desenvolvedores.
Independentemente da abordagem técnica em termos de 'desenvolvedores fazem alterações e interrompem a automação do controle de qualidade', isso é um problema do fluxo de trabalho. Você precisa ter certeza de que: todos são da mesma equipe; o desenvolvedor executa os mesmos testes integrados; os padrões são acordados e seguidos pelos dois grupos; a definição de done inclui executar e possivelmente atualizar os testes da interface do usuário; desenvolvedores e testadores fazem par de planos de teste e participam da preparação do ticket (se estiver fazendo o Agile) e falam sobre o teste da interface do usuário como parte da preparação. Você deve garantir que qualquer abordagem e estratégia usada para nomear seja coordenada com os desenvolvedores de aplicativos. Se você não chegar à mesma página, entrará em conflito com a nomeação de objetos. Alguns exemplos de métodos de objeto de página que criei recentemente para um projeto ruby:
Aqui estão os mesmos objetos de página que as variáveis javascript:
fonte
A razão pela qual as pessoas desenvolveram coisas como MVC, MVP e apresentador primeiro e padrões de design semelhantes foi separar a lógica de negócios da interface do usuário.
Obviamente, a parte da visualização só pode ser testada iniciando o programa e verificando o que mostra - em outras palavras, ela só pode ser testada em testes de aceitação.
Por outro lado, o teste da lógica de negócios pode ser feito em testes de unidade. E essa é a resposta para sua pergunta. Teste tudo no modelo e, se puder e quiser, também pode testar o código do controlador.
Isso só pode acontecer quando você muda os requisitos. Quando um requisito muda, não há como contorná-lo, exceto para modificar o código. Se você conseguir criar um bom design e arquitetura, a mudança não será propagada em muitos lugares.
fonte
Os testes de interação da GUI não devem ser mais ou menos frágeis do que qualquer outro tipo de teste. Isso é; se o seu aplicativo estiver mudando de alguma forma, os testes precisam ser atualizados para refletir isso.
Como comparação:
Teste de unidade
Original :
validateEmail()
deve lançar umaInvalidData
exceção. Qual é coberto corretamente no seu teste de unidade.Mudança :
validateEmail()
deve lançar umaInvalidEmail
exceção. Agora seu teste está incorreto, você o atualiza e tudo fica verde novamente.Teste da GUI
Original : a inserção de um email inválido resultará em uma caixa de erro pop-up contendo "Dados inválidos digitados". Detectado corretamente pelos seus testes.
Alteração : a inserção de um email inválido resultará em um erro embutido contendo "Email inválido digitado". Agora seu teste está incorreto, você o atualiza e tudo fica verde novamente.
Lembre-se de que você está testando entradas e saídas - algum comportamento bem definido. Independentemente de se tratar de um teste de GUI ou de unidade ou de integração, etc.
fonte