Por exemplo: Ao executar o teste funcional de um formulário em um aplicativo Web, testaremos os campos inserindo diferentes tipos de valores de entrada aleatórios.
Em geral, como usuários do aplicativo Web, na verdade, não inserimos valores aleatórios nos campos.
Então, qual é a utilidade de incorporar todos os casos de teste que podem / não levar a erros, quando a probabilidade de aparecer esse tipo de problema na produção é bem menor?
Nota: O exemplo acima é apenas um exemplo de caso; esses problemas podem ocorrer em qualquer tipo de recurso / módulo.
Estou fazendo essa pergunta apenas para saber se existem práticas padrão a serem seguidas ou se depende totalmente do produto, domínio e todos os outros fatores.
testing
web-applications
bug
Nagarani Dubbaka
fonte
fonte
Respostas:
Você pode não inserir valores aleatórios nos campos de um aplicativo Web, mas certamente existem pessoas por aí que fazem exatamente isso.
Algumas pessoas entram aleatoriamente por acidente e outras tentam intencionalmente interromper o aplicativo. Nos dois casos, você não deseja que o aplicativo trave ou exiba outro comportamento indesejado.
Para o primeiro tipo de usuário, você não deseja isso porque isso proporciona uma experiência ruim e pode afastá-lo.
Para o segundo tipo de usuário, eles geralmente não têm intenções honrosas e você não deseja permitir que eles tenham acesso a informações que eles não deveriam acessar ou permitir que eles neguem o acesso de usuários genuínos aos seus serviços.
A prática padrão para testes é verificar não apenas se o caso de bom tempo funciona, mas também que casos extremos incomuns são explorados para encontrar possíveis problemas e ter certeza de que os invasores não podem obter facilmente acesso ao seu sistema. Se seu aplicativo já trava com entradas aleatórias, você não quer saber o que um invasor pode fazer com entradas especialmente criadas.
fonte
Nunca assuma nada
Você não pode presumir que qualquer usuário não fará algo "estúpido" com seu software por acidente ou de propósito. Os usuários podem pressionar acidentalmente o botão errado, o gato pode passar por cima do teclado, o sistema pode funcionar mal, o computador pode ser invadido por software malicioso, etc.
Além disso, o próprio usuário pode ser malicioso, buscando intencionalmente maneiras de interromper o seu software, na esperança de encontrar uma maneira de explorá-lo em proveito próprio. Mesmo que eles encontrem um bug que não podem explorar, qualquer coisa que eles encontrem pode incentivá-lo a investigar o sistema em busca de algo que possa atacar, sabendo que seus procedimentos de controle de qualidade estão faltando.
No que diz respeito ao teste, é útil proteger-se contra entradas aleatórias, no entanto, escolher entradas de teste inteiramente aleatórias (ou seja, sem nenhuma consideração particular em relação a qualquer caso de uso ou casos extremos) é quase inútil. O objetivo do teste é validar sua solução contra os requisitos e expectativas de seu empregador / clientes / usuários; isso significa que você precisa se concentrar em direcionar todos os casos extremos e condições de contorno, bem como os casos "degenerados" que não se encaixam no fluxo de trabalho esperado do usuário.
Obviamente, você pode executar testes que revelam bugs que você decide mais tarde que não valem a pena consertar; isso pode ser por todos os tipos de razões - o bug pode ser muito caro para corrigir em relação ao seu impacto no usuário, ou você pode descobrir bugs em recursos que ninguém usa, ou o bug já está tão bem estabelecido no sistema que alguns os usuários estão tratando isso como um recurso.
Como alternativa, você pode escrever um software sob medida, com uma audiência bastante limitada de usuários 'especializados', onde não há benefício comercial em gastar tempo corrigindo bugs, porque esses usuários são capazes de fazer seus trabalhos com software com bugs (por exemplo, uma ferramenta de diagnóstico usado pela equipe interna de TI não está gerando receita, por isso, se ocorrer uma falha ocasional, é provável que ninguém queira pagar pelo tempo necessário para corrigi-lo - eles apenas solicitarão à equipe de TI que convide os bugs) .
No entanto, você só pode tomar essas decisões se souber desses bugs. Por exemplo, um usuário pode inserir uma entrada maliciosa que limpa todo o banco de dados - se você não tiver protegido e testado explicitamente esse cenário, não há como ter certeza de que isso pode ou não acontecer. O risco de deixar bugs não descobertos no sistema significa que você está potencialmente se deixando aberto a problemas reais se um desses bugs se revelar no mundo real e causar um grande impacto em seus usuários.
Portanto, embora a decisão de corrigir bugs possa exigir alguma contribuição do proprietário do software (geralmente quem paga seu salário), a decisão de testar bugs e em quais casos testar é uma preocupação de engenharia que precisa ser consignado nas estimativas e no planejamento do projeto, onde o objetivo deve ser algo o mais próximo possível da cobertura total, razoavelmente possível, dadas as restrições de tempo / dinheiro / recursos.
fonte
For example, a user may enter a malicious input which wipes the entire database - if you haven't explicitly protected against and tested for this scenario, then there's no way you can be sure whether or not this can happen.
Como as pequenas mesas de Bobby dessa história em quadrinhos do XKCD? ;)Existem vários fatores a serem levados em consideração. Para ilustrar esses pontos, usarei um exemplo de campo em que um usuário deve inserir uma porcentagem no contexto de uma cota definida para uma tarefa específica em termos de quanto espaço em disco a tarefa poderia usar. 0% significa que a tarefa não seria capaz de gravar nada no disco; 100% significa que a tarefa pode preencher todo o espaço em disco. Valores entre significam o que significam.
Como desenvolvedor, você provavelmente está considerando que os valores aceitáveis são [0, 1, 2, 3, ± 99, 100] e todo o resto é tolo. Vamos ver por que os usuários ainda podem estar inserindo esses valores "tolos".
Erros de digitação
%^
O usuário estava inserindo o valor 56, mas pressionou por engano Shiftao digitá-los (por exemplo, porque no teclado francês, é necessário pressionar Shiftpara inserir dígitos, e o usuário alternava constantemente entre um teclado francês e um QWERTY).
Da mesma forma, você pode obter um número, com algo antes ou depois dele, ou entre:
56q
Aqui, o usuário provavelmente estava inserindo os dígitos, seguido por uma guia para ir para o próximo campo. Em vez de pressionar ⇆ , o usuário pressionou a tecla vizinha.
Mal-entendidos e más interpretações
Uma entrada vazia é provavelmente a mais comum. O usuário imaginou que o campo era opcional ou não sabia o que colocar nesse campo.
56.5
O usuário achou que os valores de ponto flutuante eram aceitáveis. O usuário está errado e o aplicativo deve educadamente explicar por que apenas valores inteiros são aceitos ou se os requisitos iniciais estavam errados, e faz sentido permitir que os usuários insiram valores de ponto flutuante.
none
O usuário entendeu mal que, quando solicitado pelo espaço que a tarefa poderia ocupar, o aplicativo esperava um número. Isso pode indicar uma interface de usuário ruim. Por exemplo, perguntar ao usuário "Quanto espaço em disco a tarefa deve levar?" Convida a esse tipo de entrada, enquanto um campo com um sinal de porcentagem a seguir receberia menos desse tipo de entrada, porque "none%" não gera muito sentido.
150
O usuário não entendeu o que a porcentagem significa neste caso. Talvez o usuário queira dizer que a tarefa pode ocupar 150% do espaço usado atualmente; portanto, se um disco de 2 TB for usado com 100 GB, a tarefa poderá usar 150 GB. Novamente, uma interface de usuário melhor poderia ajudar. Por exemplo, em vez de ter um campo de entrada vazio com um sinal de porcentagem anexado, pode-se ter o seguinte:
Quando o usuário começa a digitar, ele muda o texto rapidamente para se tornar o seguinte:
Representações
Números grandes ou números com um ponto flutuante podem ser representados de maneira diferente. Por exemplo, um número 1234,56 poderia ser escrito assim:
1,234.56
. Dependendo da cultura, a representação em texto do mesmo número seria diferente. Em francês, o mesmo número será escrito assim:1 234,56
. Veja, uma vírgula onde você não esperaria uma, e um espaço.Sempre esperar um formato específico usando uma localidade específica poderia causar problemas mais cedo ou mais tarde, porque usuários de diferentes países teriam hábitos diferentes de escrever números, datas e horas, etc.
Humanos vs. computadores
Twenty-four
Os seres humanos comuns não pensam da mesma maneira que os computadores. "Vinte e quatro" é um número real, independentemente do que um PC diria.
Embora (1) a maioria dos sistemas não lide com esse tipo de entrada e (2) quase todos os usuários não imaginem inserir um número escrito em letras completas, isso não significa que essa entrada seja boba. No About Face 3 , Alan Cooper afirma que o não manuseio dessas entradas é indicativo da incapacidade dos computadores de se adaptarem aos seres humanos e, idealmente, a interface deve ser capaz de lidar com essas entradas corretamente.
A única coisa que tenho que acrescentar ao livro de Alan Cooper é que, em muitos casos, os números são escritos em dígitos por engano . O fato de os computadores esperarem que seus usuários cometam erros (e não toleram um usuário que escreve corretamente) é irritante.
Unicode
5𝟨
O Unicode reserva suas próprias surpresas: caracteres que podem parecer iguais não são os mesmos. Não convencido? Copie e cole
"5𝟨" === "56"
nas ferramentas de desenvolvedor do seu navegador e pressione Enter.O motivo de essas cadeias não serem iguais é que o caractere Unicode
𝟨
não é o mesmo que o caractere6
. Isso criaria uma situação em que um cliente irritado ligaria, informando que seu aplicativo não está funcionando, fornecendo uma captura de tela de uma entrada que parece legítima e seu aplicativo alegando que a entrada é inválida.Por que alguém digitaria um caractere Unicode que se parece com um dígito, você perguntaria? Embora eu não espere que um usuário entre sem querer, uma cópia e colagem de uma fonte diferente poderia causar isso, e eu tive um caso em que o usuário realmente fez essa cópia e colagem de uma string que continha um caractere Unicode que não aparecer na tela.
Conclusão
Esses são os casos que você obtém para um campo de entrada de número elementar. Gostaria de imaginar o que você pode lidar com formulários mais complexos, como uma data ou um endereço.
Minha resposta está focada no que você chamou de entrada "boba". Testar não é verificar os caminhos felizes; também se trata de verificar se o aplicativo não quebra quando um usuário mal intencionado entra intencionalmente em coisas estranhas, tentando quebrá-lo. Isso significa que, quando você solicita uma porcentagem, também precisa testar o que acontece quando o usuário está respondendo com uma sequência contendo 1.000.000 caracteres, ou um número negativo ou uma tabela de bobby .
fonte
1 234,56
sequência de caracteres (usando U + 00A0 NO-BREAK SPACE em vez de U + 0020 SPACE), que é a maneira correta de codificar esses marcadores de número (ou com U + 202F ESPAÇO SEM INTERRUPÇÃO, PEROAPS). Copiar o valor de qualquer aplicativo que formate os números de acordo com o código do idioma antes de apresentá-lo ao usuário produziria isso com muita facilidade.Há muitas boas respostas aqui que descrevem por que isso é importante, mas não muitos conselhos sobre como proteger seu aplicativo de maneira sensata. A "prática padrão" é usar validação de entrada robusta, no cliente e no servidor. Entrada não sensível é fácil de se defender; você simplesmente rejeita qualquer coisa que não faça sentido nesse contexto específico. Por exemplo, um número de previdência social consiste apenas de traços e dígitos; você pode recusar com segurança qualquer outra coisa que o usuário digitar em um campo de número de segurança social.
Existem dois tipos de teste que devem ocorrer em todos os aplicativos que você escreve e cada um tem finalidades diferentes. O teste que você faz em seu próprio aplicativo é positivo; seu objetivo é provar que o programa funciona. O teste que os testadores fazem adicionalmente em seu aplicativo é negativo; seu objetivo é provar que seu programa não funciona. Por que você precisa disso? Porque você não é a melhor pessoa para testar seu próprio software. Afinal, você escreveu a coisa, então obviamente já funciona, certo?
Ao escrever a validação de entrada, você empregará testes positivos para provar que sua validação funciona. Os testadores usarão entradas aleatórias para tentar provar que não funciona. Observe que o espaço problemático para entradas aleatórias é essencialmente ilimitado; seu objetivo não é testar todas as permutações possíveis, mas limitar o espaço do problema rejeitando entradas inválidas.
Observe também que o usuário final não é o único a fornecer informações ao seu programa. Cada classe que você escreve tem sua própria API e suas próprias restrições sobre o que é considerado entrada válida, portanto, a validação robusta (ou seja, "contratos de código") também é importante para as suas classes. A idéia é fortalecer o software para que comportamentos inesperados sejam raros ou inexistentes na máxima extensão possível.
Finalmente, o fluxo de trabalho é importante. Eu vi aplicativos caírem, não porque o usuário inseriu algo não sensorial, mas porque eles fizeram as coisas no aplicativo em uma ordem inesperada. Seu aplicativo deve estar ciente dessa possibilidade e lidar com fluxos de trabalho inesperados normalmente ou exigir que o usuário execute operações na ordem especificada.
fonte
Normalmente, os valores 'aleatórios' não são aleatórios. Você está tentando capturar casos extremos, o "desconhecido desconhecido".
Digamos, por exemplo, que o caractere # trava seu aplicativo. Você não sabe disso com antecedência e seria impossível escrever casos de teste para todas as entradas possíveis. Mas podemos escrever um teste
"¬!"£$%^&*()_+-=[]{};'#:@~,./<>?|\"
e ver se ele quebrafonte
Certa vez, escrevi um programa que testei em um laboratório com 60 alunos. Eu estava atrás das 60 telas de computador e as vi usá-las. A quantidade de coisas ridículas que eles fizeram foi arrepiante. Eu estava encharcado de suor assistindo a "criatividade" deles. Eles fizeram muito mais do que qualquer indivíduo pode fantasiar durante a vida. Claro que um deles quebrou.
Depois disso, sigo uma abordagem:
if "a very specific use case" do, else show error
Se eu tiver vários casos de uso, eu os defino estritamente e encadeio os itens acima.
fonte
O que você está descrevendo é Fuzzing ou Fuzz Testing : jogue entradas aleatórias e inválidas em um sistema e veja o que acontece. Você não faz isso porque espera que um usuário faça isso. Você faz isso para expor suas próprias suposições e preconceitos para forçar as bordas do seu sistema e ver o que acontece.
A entrada de teste normal escrita por um humano com virá com suposições e preconceitos. Esses vieses podem ser que certas classes de bugs nunca são encontradas no teste.
Por exemplo, se a maior parte de sua entrada estiver no intervalo Unicode seguro para ASCII, não serão utilizadas suposições sobre a codificação de caracteres no código. Ou talvez esteja sempre abaixo de um determinado tamanho, para que um campo ou buffer de tamanho fixo não seja atingido. Ou talvez haja caracteres especiais que sejam interpretados de maneiras surpreendentes, expondo que a entrada do usuário está sendo alimentada em um shell ou usada para criar consultas de maneira insegura. Ou talvez exista muito teste de "caminho feliz" e tentativas insuficientes para exercitar o tratamento de erros.
Fuzzing não tem esses preconceitos sobre entrada. Exercitará brutalmente o seu sistema com qualquer combinação possível de entrada "válida". Unicode, ASCII, grande, pequeno e muitos erros. Seu sistema deve responder normalmente a todos eles. Nunca deve falhar. O usuário sempre deve receber algum tipo de mensagem sensata sobre o que deu errado e como corrigi-lo. Não é Garbage In / Garbage Out, é Garbage In / Error Out .
Embora se possa descartar as explosões resultantes porque "nenhum usuário real fará isso", isso perde o sentido do exercício. Fuzzing é uma maneira barata de eliminar seus preconceitos sobre possíveis entradas. É uma maneira barata de lançar todas as coisas estranhas que os usuários tentarão fazer no seu sistema. Como engenheiro, seu trabalho é garantir que seu sistema falhe normalmente.
Além disso, a difusa "entrada" não se refere apenas aos usuários. Pode representar o resultado de uma consulta da API a um serviço de terceiros. E se isso começar a enviar resultados confusos? Como o seu sistema lida com isso? Um sistema adequado deve alertar um administrador que um componente está com problemas. Um sistema inadequado rejeitará silenciosamente a consulta incorreta ou, pior, a aceitará como bons dados.
Finalmente, alguns usuários são maliciosos. Se você não testar o seu sistema, alguém o fará. Eles investigam as bordas do seu sistema quanto a erros comuns e tentam usá-los como brechas de segurança. O teste do Fuzz pode simular isso, até certo ponto, e você pode lidar com quaisquer possíveis falhas de segurança descobertas antes que elas se tornem um problema.
fonte
Se seu objetivo é criar um produto de qualidade, teste todos os tipos possíveis de entrada que um usuário poderá fisicamente enviar. Caso contrário, você estará apenas aguardando o dia em que alguém enviar esse tipo de entrada que você não achou necessário testar.
Durante uma grande demonstração do novo software de leilão eletrônico em uma autoridade local onde eu trabalhava, meu gerente decidiu (reconhecidamente com algumas brincadeiras) que sentia a necessidade de ver o que acontecia se ele fizesse uma oferta de leilão com um valor negativo. Para minha surpresa genuína, o software de leilão permitiu essa oferta sem sentido e todo o processo de leilão foi interrompido. O tipo de leilão demonstrado nunca deve permitir o envio de valores negativos.
Alguns do grande grupo de oficiais de compras e finanças reunidos ficaram aborrecidos com meu gerente por apresentar um valor sem sentido. Mas outros, inclusive eu, ficaram aborrecidos com os desenvolvedores de software por não testarem e rejeitarem um tipo tão óbvio de entrada inválida. Só posso imaginar o quão fraco o software deve ter sido ao desviar outros tipos de entrada inválida (tentativas de injeção de código, caracteres exóticos não representáveis na tabela do banco de dados, etc.).
Se dependesse de mim, eu teria devolvido o software e o julgaria impróprio. A diferença entre um produto de software fraco e um forte é o nível de teste ao qual foi submetido.
fonte
test every possible type of input that a user will be physically able to submit.
- Esse espaço problemático é essencialmente infinito e você está perdendo seu tempo tentando testar tudo. Verificar entradas negativas é uma única bifurcação; não é apenas sensato, mas também esperado de desenvolvedores competentes. Você não precisa verificar todos os números negativos para provar que essa validação funciona.Sim. Este é um tipo de teste, mas não é um teste funcional . Isso é chamado de teste de estresse . É o ato de aplicar pressão a um sistema para ver se ele pode lidar com isso.
Quando você é um software de teste de estresse , está tentando descobrir os limites de quais são os limites do software.
Os testes são, de certa forma, exaustivos por natureza. Onde você precisa descobrir limites de uso, pontos de interrupção, verificar todas as ramificações lógicas ou ver como falhas parciais afetam todo o sistema.
Você pode passar todos os seus testes funcionais, mas ainda falhar no teste de estresse .
Sim, esta é uma prática padrão.
O teste de software consiste em fazer uma pergunta sobre o comportamento esperado e, quando todos os testes passam, isso comunica que o software opera como pretendido. É por isso que os testes criam boas condições para a implantação de atualizações.
O teste de estresse não fornece indicadores específicos claros de aprovação ou reprovação. Os resultados são mais informativos. Ele diz com o que o seu sistema pode lidar e você toma decisões com base nessas informações.
Você pode definir metas específicas para testes de estresse que devem ser aprovadas para continuar no próximo estágio de desenvolvimento. Eles podem ser incluídos como parte do seu processo de garantia de qualidade, mas as mudanças no ambiente podem alterar os resultados de um teste de estresse. Portanto, as pessoas realizam testes de estresse em momentos diferentes para ver como o sistema lida com as mudanças nas condições.
O que quero dizer é que você não pode simplesmente executar testes de estresse toda vez que implantar uma nova versão do seu software e assumir que isso significa que tudo passará no teste de estresse posteriormente.
fonte