|
Essa diretriz mostra como identificar ideias de teste a partir de gráficos de estado e outras estruturas de design que consistem principalmente de nós ligados por arcos e que mostram algo dos possíveis fluxos de controle de um programa. O principal objetivo destes testes é percorrer todos os arcos em algum teste. Se você nunca exercitou um arco, por que acha que irá funcionar quando um cliente fizer?
Considere este gráfico de estado:
Fig1: Gráfico de estado HVAC
Aqui está uma primeira lista de ideias de teste:
- o estado Idle recebe o evento Too Hot
- o estado Idle recebe o evento Too Cool
- o estado Cooling/Startup recebe o evento Compressor Running
- o estado Cooling/Ready recebe o evento Fan Running
- o estado Cooling/Running recebe o evento OK
- o estado Cooling/Running recebe o evento Failure
- o estado Failure recebe o evento Failure Cleared
- o estado Heating recebe o evento OK
- o estado Heating recebe o evento Failure
Todas estas ideias de teste poderiam ser exercitadas em um único teste, ou você poderia criar vários testes onde cada um exercitaria algumas. Tal como todo design de testes, procure equilíbrio entre a facilidade de implementação de muitos testes simples e o poder adicional de busca de defeitos dos testes complexos. (veja "design de teste usando a lista" na página Conceito: Lista de Ideias de Teste). Se você tiver cenários de caso de uso que descrevam alguns caminhos no gráfico de estado, você deverá favorecer os testes que percorram esses caminhos.
Em todos os casos, os testes devem verificar se todas as ações exigidas pelo gráfico de estado foram efetivamente contempladas. Por exemplo, o alarme foi ativado na entrada do estado Failure e desativado após a saída?
O teste também deve verificar que a transição leva ao próximo estado correto. Isto pode ser um grande problema se os estados forem exteriormente invisíveis. A única forma de detectar um estado incorreto é injetar uma sequência de eventos que conduzam a uma saída incorreta. Mais precisamente, você precisa construir uma sequência contínua de eventos, cujos resultados externamente visíveis para o estado correto difiram daqueles gerados pela mesma sequência para cada estado incorreto possível.
No exemplo acima, como você sabe se o evento Failure Cleared no estado Failure direciona corretamente para o estado Idle, ao invés de ficar no estado Failure? Você poderia acreditar que a desativação do Alarme significaria que a transição aconteceu, mas poderia ser melhor verificado, baixando a temperatura o suficiente para acionar o aquecedor ou aumentando-a o suficiente para acionar a refrigeração. Se algo acontecer, você estará mais confiante de que a transição foi correta. Se nada acontecer, é provável que o dispositivo tenha ficado no estado Failure.
Pelo menos, determinar se o estado resultante é correto complica o design do teste. E sempre melhor tornar a máquina de estado explícita e seus estados visíveis para os testes.
Outras construções de gráficos de estado
Os gráficos de estado consistem mais do que arcos e flechas. Aqui está uma lista de construções de gráficos de estado e o efeito que causam na lista de ideias de teste.
Ações de evento, ações de entrada e ações de saída
Estes não geram ideias de teste por si só. Ao invés, os testes devem verificar que as ações comportam-se como o especificado. Se as ações representam programas substanciais, esses programas devem ser testados. As ideias de teste para os programas podem ser combinadas com as ideias de teste do gráfico de estado, mas será provavelmente muito mais gerenciável se ficarem separadas. Tome a decisão com base no esforço envolvido e em suas suspeitas de que possam existir interações entre os eventos. Ou seja, se uma determinada ação em um arco não puder compartilhar dados com uma ação em outro arco, não há nenhuma razão para exercitar as duas ações no mesmo teste (como você faria se fossem parte do mesmo caminho em um teste de gráfico de estado).
Condições de guarda
As condições de guarda são expressões booleanas. As ideias de teste para as condições de guarda são derivadas, como descrito em Guideline: Ideias de Teste Para Valores Limítrofes e Booleanos.
No exemplo acima, a transição Too Cool do estado Idle está guardada com [restart time >= 5 mins]. Isto conduz a duas ideias de teste distintas:
- O estado Idle recebe o evento Too Cool quando o tempo de reinício for igual a cinco minutos (transição acontecida)
- O estado Idle recebe o evento Too Cool quando o tempo de reinício for um pouco menor que cinco minutos (transição bloqueada)
Em ambos os casos, qualquer teste que use a ideia de teste deve verificar se o estado correto foi atingido.
Transições internas
Uma transição interna acrescenta o mesmo tipo de ideias a uma lista de ideias de teste da mesma forma que uma transição externa. Simplesmente, o próximo estado é o mesmo do estado original. Seria prudente configurar o teste de forma que as ações de entrada e saída do estado pudessem causar um efeito observável se elas fossem acionadas incorretamente.
Estados aninhados
Ao construir testes, configure-os de tal forma que os eventos de entrada e saída do estado composto tenham efeitos observáveis. Você precisa notar se eles forem ignorados.
Sub-estados concorrentes
Os testes de concorrência estão fora do escopo dos testes de desenvolvedor.
Eventos adiados
Se você suspeitar que um evento possa ser tratado de forma diferente, dependendo se ele foi adiado e enfileirado, em vez de gerado enquanto o programa estava realmente no estado de recepção, você poderá testar os dois casos.
Se o evento no estado de recepção tiver uma condição de guarda, considere as implicações das mudanças nas variáveis de condição entre o momento que o evento é gerado e o momento em que é recebido.
Se mais de um estado puder tratar um evento adiado, considere testar o adiamento para cada um dos estados de recepção possíveis. Talvez a implementação assuma que o estado "óbvio" irá tratar o evento.
Estados históricos
Aqui está um exemplo de um estado histórico:
Fig2: Exemplo de Estado Histórico
A transição para o estado histórico representa três transições reais, e três ideias de teste:
- O evento BackingUp no estado Command conduz ao estado Collecting
- O evento BackingUp no estado Command conduz ao estado Copying
- O evento BackingUp no estado Command conduz ao estado CleaningUp
Cadeia de estados
A cadeia de estados não parece ter quaisquer implicações no design de teste, exceto que ela introduz mais ações que precisam ser verificadas.
A discussão anterior focava na verificação de que a implementação correspondia ao design. Mas o design também poderá estar errado. Ao examinar o design para encontrar ideias de teste, verifique também dois tipos de problemas:
Eventos esquecidos. O gráfico de estado mostra uma resposta do estado aos eventos que o designer achou que poderiam chegar nesse estado. Não é incomum que os designers ignorem eventos. Por exemplo, neste gráfico de estado (igual ao do topo da página), talvez o designer tenha esquecido que possa ocorrer uma falha no sub-estado Ready de Cooling, não somente quando a ventoinha estiver Running.
Fig3: Gráfico de estados HVAC
Por esta razão, é sensato perguntar, para cada estado, se algum dos eventos que se aplicam a outros estados poderá ser aplicado a ele. Se você descobrir que existe algum, corrija o seu design.
Condições de guarda incompletas ou esquecidas. Do mesmo modo, talvez as condições de guarda em uma transição irão sugerir condições de guarda em outras. Por exemplo, o gráfico de estado acima toma cuidado para não reiniciar o aquecedor muitas vezes, mas não há essa restrição no sistema de refrigeração. Deveria existir?
Também é possível que variáveis usadas em uma condição de guarda sugiram que outras condições de guarda são muito simples.
Testar cada arco em um gráfico não é uma forma de teste completo. Por exemplo, suponha que o estado de início inicialize uma variável em 0, o estado Setter a defina como 5 e o estado Divider divida 100 por ela (100/variável). Se houver um caminho do estado inicial ao Divider que não passe por Setter, você terá uma exceção de divisão por zero. Se o gráfico de estado tiver muitos estados, exercitar simplesmente cada arco poderá não considerar esse caminho.
Exceto para gráficos de estados muito simples, os testes de todos os caminhos é inexequível. Na prática, os testes que são complexos e que correspondem aos cenários do caso de uso são normalmente suficientes. Se você desejar testes mais fortes, considere exigir um caminho de cada estado onde um dado forneça um valor para cada estado que o usa. |