Baixe o app para aproveitar ainda mais
Prévia do material em texto
Universidade Federal do Rio Grande do Norte Centro de Ciências Exatas e da Terra Departmento de Informática e Matemática Aplicada Programa de Pós-Graduação em Sistemas e Computação Mestrado Acadêmico em Sistemas e Computação O Framework ConBaT: Suporte a Testes Baseados em Contexto para Sistemas Desenvolvidos em Arduino Lucas Rodrigues Silva Natal-RN Abril, 2021 Lucas Rodrigues Silva O Framework ConBaT: Suporte a Testes Baseados em Contexto para Sistemas Desenvolvidos em Arduino Dissertação de Mestrado apresentada ao Pro- grama de Pós-Graduação em Sistemas e Computação do Departamento de Informá- tica e Matemática Aplicada da Universidade Federal do Rio Grande do Norte como re- quisito parcial para a obtenção do grau de Mestre em Sistemas e Computação. Linha de pesquisa: Engenharia de Software Orientadora Profa. Dra. Roberta de Souza Coelho PPgSC – Programa de Pós-Graduação em Sistemas e Computação DIMAp – Departamento de Informática e Matemática Aplicada CCET – Centro de Ciências Exatas e da Terra UFRN – Universidade Federal do Rio Grande do Norte Natal-RN Abril, 2021 Silva, Lucas Rodrigues. O Framework ConBaT: suporte a testes baseados em contexto para sistemas desenvolvidos em Arduino / Lucas Rodrigues Silva. - 2021. 115f.: il. Dissertação (mestrado) - Universidade Federal do Rio Grande do Norte, Centro de Ciências Exatas e da Terra, Programa de Pós- graduação em Sistemas e Computação. Natal, 2021. Orientadora: Profa. Dra. Roberta de Souza Coelho. 1. Computação - Dissertação. 2. Teste de software - Dissertação. 3. Arduino - Dissertação. 4. Sistemas sensíveis ao contexto - Dissertação. 5. Sistemas dependentes de contexto - Dissertação. 6. Testes baseados em contexto - Dissertação. 7. Sistemas embarcados - Dissertação. I. Coelho, Roberta de Souza. II. Título. RN/UF/CCET CDU 004 Universidade Federal do Rio Grande do Norte - UFRN Sistema de Bibliotecas - SISBI Catalogação de Publicação na Fonte. UFRN - Biblioteca Setorial Prof. Ronaldo Xavier de Arruda - CCET Elaborado por Joseneide Ferreira Dantas - CRB-15/324 O Framework ConBaT: Suporte a Testes Baseados em Contexto para Sistemas Desenvolvidos em Arduino Autor: Lucas Rodrigues Silva Orientadora: Profa. Dra. Roberta de Souza Coelho Resumo Sistemas embarcados, em especial os sistemas embarcados dependentes do contexto no qual estão inseridos, isto é, cujo comportamento é determinado por informações constan- temente obtidas através dos mais diversos tipos de sensores, podem ser muito difíceis de serem testados. Isso porque além de serem sistemas com recursos naturalmente limitados, a natureza de seus dados de entrada dificulta sua replicação. Desta forma, abordagens de teste de software que funcionam muito bem em sistemas “comuns” podem ser insuficien- tes para esse tipo de sistema. Grande parte das ferramentas criadas até o momento se limitam à criação de testes de unidade, evitando lidar com dados recebidos diretamente de sensores, que são na verdade a base do funcionamento dos sistemas dependentes do contexto. Trabalhos que suportam a simulação de informações de contexto, como estra- tégias baseadas em eventos, em grande parte abstraem a tradução dos dados crus dos sensores em informação útil para o sistema, deixando esta etapa de fora dos testes. Para auxiliar a atividade de testes em sistemas embarcados sensíveis ao contexto, este trabalho traz como contribuições: (i) uma abordagem para armazenar a variação de dados de con- texto sob diferentes perspectivas (sensores) de forma sensível ao tempo e independente de aplicações, em arquivos denominados context files e (ii) o framework ConBaT (Context Based Testing), com o propósito de auxiliar a coleta de dados de contexto, gerando con- text files bem documentados, e a criação de testes baseados em contexto para sistemas desenvolvidos em Arduino, fornecendo suporte à simulação de sensores de forma sensível ao tempo. Palavras-chave: Teste de software, Arduino, Sistemas sensíveis ao contexto, Sistemas de- pendentes de contexto, Testes baseados em contexto, Sistemas embarcados. ConBaT: A framework to support the testing of context-aware Arduino system Author: Lucas Rodrigues Silva Supervisor: Roberta de Souza Coelho Abstract Embedded systems, especially context-aware embedded systems, whose behaviour is de- termined by information constantly obtained from different kinds of sensors, can be very hard to be tested. That happens due to the nature of their input data, which can be hard to replicate, and also because of their limited resources. Thus, software testing techniques that may work for “common” software can be insufficient for this kind of system. Tools created to support the testing activity of embedded systems are often limited to unit tests, and avoid having to deal with data received from sensors, which is actually the foundation of context-aware systems’ behaviour. Those that support context simulation, like event-based approaches, generally abstract the translation of raw sensor data into useful information (the events), leaving this stage out of the tests. To support software testing on context-aware embedded systems, this work proposes (i) a time-sensitive and application-independent format to store context data variation over time, called context file, and (ii) the framework ConBaT (Context Based Testing), that can be used to collect context data, generating context files, as well as to create context based tests for Arduino systems, supporting time-sensitive sensor simulation. Keywords : Software testing, Arduino, Context-aware systems, Context driven testing, Embedded systems. Lista de figuras 1 Representação do loop de execução de um sistema dependente do contexto p. 14 2 Loop principal do sistema de iluminação automática . . . . . . . . . . . . p. 15 3 Refatoração do código para facilitar a criação de testes de unidade . . . . p. 15 4 Visão geral dos componentes de um sistema desenvolvido para Arduino . . p. 21 5 Modelo V proposto por Craig e Jaskiel, 2002 . . . . . . . . . . . . . . . . p. 24 6 Exemplo de teste de unidade simples criado com JUnit 4 . . . . . . . . . . p. 38 7 Feedback visual do resultado dos testes da Figura 6, na IDE Eclipse4 . . . p. 38 8 Uso de capture replay para testar um sistema sensível ao contexto . . . . . p. 41 9 Dados coletados durante a fase de captura em comparação aos momentos em que esses dados são fornecidos pelo objeto mock durantes os testes, ao longo do tempo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 42 10 Variação real dos dados ao longo do tempo, comparados aos dados coletados durante a fase de captura e aos dados fornecidos pelo objeto mock durante testes, após alteração na taxa de leitura dos sensores pelo sistema . . . . . p. 43 11 À esquerda, dados coletados pelo próprio sistema a ser testado. À direita, dados coletados pelo sistema de coleta, em relação ao tempo . . . . . . . p. 43 12 Exemplo de um context file . . . . . . . . . . . . . . . . . . . . . . . . . p. 46 13 Visão geral das atividades envolvidas durante a coleta de dados e criação de testes com o ConBaT . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 50 14 Componentes do sistema sob testes . . . . . . . . . . . . . . . . . . . . . p. 51 15 Script genérico de coleta . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 52 16 Configuração da coleta de dados . . . . . . . . . . . . . . . . . . . . . . p. 53 17 Código do sistema adaptado para comunicação com o ConBaT . . . . . . p. 54 18 Testes criados pelo ConBaT para o context file C001, em conjunto com JUnit 4 p. 56 19 Visão geral da arquitetura do A-ConBaT (Arduino) e ConBaT (Java) . . . p. 58 20 Classes relacionadas à manipulação de context files . . . . . . . . . . . . . p. 59 21 Métodos do Messenger, responsáveis por receber mensagens . . . . . . . . p. 60 22 Classes responsáveis pela comunicação no lado Java . . . . .. . . . . . . p. 62 23 Parâmetros referentes à coleta e criação de context files . . . . . . . . . . p. 63 24 Exemplo de coleta e criação de um context file . . . . . . . . . . . . . . . p. 65 25 Context file gerado a partir do código da Figura 24 . . . . . . . . . . . . . p. 66 26 Implementação do método collectAndSave() da classe ContextCollector . . p. 67 27 Diagrama de classes do módulo de coleta do ConBaT . . . . . . . . . . . p. 68 28 Diagrama de sequência, representando a comunicação entre A-ConBaT e ConBaT durante uma coleta de dados . . . . . . . . . . . . . . . . . . . . p. 69 29 Diagrama de classes do módulo de testes do A-ConBaT . . . . . . . . . . p. 70 30 Exemplo de adaptações necessárias para que um sistema seja testado pelo framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 71 31 Diagrama de classes do módulo de testes do ConBaT . . . . . . . . . . . p. 73 32 Diagrama das classes relacionadas às condições de sucesso e/ou falha de testes p. 77 33 Diagrama de classes do módulo de testes, com exceções . . . . . . . . . . p. 78 34 Diagrama de atividades representando o método checkAll() do ConditionSet p. 79 35 Esquema do sistema sob testes . . . . . . . . . . . . . . . . . . . . . . . p. 82 36 Partitura da música da qual originou-se a famosa batida “tan, tantantan, tan. . . tan, tan!” e a sequência de números (compreendida pelo sistema) que representa a proporção dos intervalos de tempo entre cada nota . . . . p. 83 37 Figuras rítmicas encontradas em uma partitura . . . . . . . . . . . . . . . p. 83 38 Intensidade da vibração detectada pelo sensor ao longo do tempo, no context file C001 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 84 39 Intensidade da vibração detectada pelo sensor ao longo do tempo, no context file C002 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 85 40 Intensidade da vibração detectada pelo sensor ao longo do tempo, no context file C003 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 85 41 Intensidade da vibração detectada pelo sensor ao longo do tempo, no context file C004 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 86 42 Intensidade da vibração detectada pelo sensor ao longo do tempo, no context file C005 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 86 43 Comparação da proporção dos intervalos de tempo entre as batidas armaze- nadas nos context files C001 e C005 . . . . . . . . . . . . . . . . . . . . p. 87 44 Exemplo em que a execução do teste é prejudicada devido ao atraso causado por trocas de mensagem entre o Arduino e o computador5 . . . . . . . . . p. 92 Lista de tabelas 1 Memória disponível em diferentes chips utilizados por placas Arduino. . . . p. 22 2 Tabela de sensores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 51 3 Tabela de atuadores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 51 4 Tabela de context files. . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 53 5 Mapeamento entre sensores e dados dos context files. . . . . . . . . . . . p. 55 6 Casos de teste. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 57 7 Tempo de execução dos testes por context file utilizado. . . . . . . . . . . p. 87 8 Número de leituras obtidas durante 5 segundos e intervalo médio entre lei- turas para diferentes valores de baud rate, sem interação com o ConBaT. . p. 90 9 Número de leituras obtidas durante 5 segundos e intervalo médio entre lei- turas para diferentes valores de baud rate, durante uma coleta real de dados com o ConBaT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 90 10 Número de mensagens enviadas durante 5 segundos e intervalo médio entre envios para diferentes tamanhos de mensagem. . . . . . . . . . . . . . . . p. 91 Sumário 1 Introdução p. 14 1.1 Limitações das abordagens atuais . . . . . . . . . . . . . . . . . . . . . p. 16 1.2 Solução proposta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 17 1.3 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 17 1.4 Organização do texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 18 2 Fundamentação Teórica p. 19 2.1 Contexto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 19 2.2 Sistemas sensíveis ao contexto . . . . . . . . . . . . . . . . . . . . . . . p. 20 2.3 Sistemas embarcados . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 20 2.4 Arduino . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 21 2.5 Sistemas Reativos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 22 2.6 Teste de software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 23 2.6.1 Conceitos básicos . . . . . . . . . . . . . . . . . . . . . . . . . . p. 23 2.6.2 Níveis de teste e o modelo V . . . . . . . . . . . . . . . . . . . . p. 23 2.6.3 Atividades de Teste . . . . . . . . . . . . . . . . . . . . . . . . . p. 24 2.6.4 Critérios de teste . . . . . . . . . . . . . . . . . . . . . . . . . . p. 25 2.6.4.1 Critérios estruturais . . . . . . . . . . . . . . . . . . . p. 25 2.6.4.2 Critérios funcionais . . . . . . . . . . . . . . . . . . . . p. 26 2.6.4.3 Critérios baseados em defeitos . . . . . . . . . . . . . . p. 26 2.6.5 Objetos mock . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 27 2.7 Automação de testes . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 27 2.7.1 Capture replay e automação . . . . . . . . . . . . . . . . . . . . p. 29 2.7.2 Técnicas de scripting . . . . . . . . . . . . . . . . . . . . . . . . p. 30 2.7.3 Automação da comparação de resultados . . . . . . . . . . . . . p. 32 2.7.4 Métricas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 33 2.7.4.1 Manutenibilidade . . . . . . . . . . . . . . . . . . . . . p. 34 2.7.4.2 Eficiência . . . . . . . . . . . . . . . . . . . . . . . . . p. 34 2.7.4.3 Confiabilidade . . . . . . . . . . . . . . . . . . . . . . p. 35 2.7.4.4 Flexibilidade . . . . . . . . . . . . . . . . . . . . . . . p. 35 2.7.4.5 Usabilidade . . . . . . . . . . . . . . . . . . . . . . . . p. 36 2.7.4.6 Robustez . . . . . . . . . . . . . . . . . . . . . . . . . p. 36 2.7.4.7 Portabilidade . . . . . . . . . . . . . . . . . . . . . . . p. 37 2.8 JUnit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 37 3 Abordagem proposta p. 39 3.1 Variação do contexto como entrada para testes . . . . . . . . . . . . . . p. 39 3.2 Exemplo motivador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 40 3.3 Visão geral da abordagem proposta . . . . . . . . . . . . . . . . . . . . p. 44 3.3.1 Context files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 44 3.3.2 Benefícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 45 3.3.3 Outros cenários de uso . . . . . . . . . . . . . . . . . . . . . . . p. 47 3.4 Considerações finais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 47 4 O framework ConBaT p. 49 4.1 Cenário de uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 49 4.1.1 O sistema sob testes . . . . . . . . . . . . . . . . . . . . . . . . p. 50 4.1.2 Coleta de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 51 4.1.3 Criação dos testes . . . . . . . . . . . . . . . . . . . . . . . . . . p. 53 4.2 Visão geral da arquitetura . . . . . . . . . . . . . . . . . . . . . . . . . p. 57 4.2.1 Context files e a classe Context . . . . . . . . . . . . . . . . . . p. 57 4.2.2 A comunicação Arduino-Computador . . . . . . . . . . . . . . . p. 58 4.3 O módulo de coleta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 62 4.3.1 O módulo de coleta do lado Arduino . . . . . . . . . . . . . . . p. 62 4.3.2 O módulo de coleta do lado Java . . . . . . . . . . . . . . . . . p. 63 4.3.3 A troca de mensagens. . . . . . . . . . . . . . . . . . . . . . . p. 65 4.4 O módulo de testes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 67 4.4.1 O módulo de testes do lado Arduino . . . . . . . . . . . . . . . p. 67 4.4.2 O módulo de testes do lado Java . . . . . . . . . . . . . . . . . p. 71 4.4.2.1 As condições . . . . . . . . . . . . . . . . . . . . . . . p. 73 4.4.2.2 O fluxo de exceções . . . . . . . . . . . . . . . . . . . . p. 76 4.4.2.3 O fluxo de mensagens . . . . . . . . . . . . . . . . . . p. 78 4.5 Considerações finais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 80 5 Avaliação p. 81 5.1 Estudo 1: Testando um sistema de trava automática de portas, controlada por códigos de batidas . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 81 5.1.1 O sistema sob testes . . . . . . . . . . . . . . . . . . . . . . . . p. 81 5.1.2 A coleta de dados . . . . . . . . . . . . . . . . . . . . . . . . . . p. 84 5.1.3 Criação dos testes e resultados . . . . . . . . . . . . . . . . . . . p. 86 5.1.4 Limitações observadas . . . . . . . . . . . . . . . . . . . . . . . p. 88 5.2 Estudo 2: investigação das limitações da arquitetura . . . . . . . . . . . p. 88 5.2.1 Análise do módulo de coleta . . . . . . . . . . . . . . . . . . . . p. 89 5.2.1.1 Variação da baud rate . . . . . . . . . . . . . . . . . . p. 89 5.2.1.2 Variação do tamanho da mensagem . . . . . . . . . . . p. 91 5.2.2 Análise do módulo de testes . . . . . . . . . . . . . . . . . . . . p. 91 5.2.3 Considerações finais . . . . . . . . . . . . . . . . . . . . . . . . . p. 94 6 Trabalhos relacionados p. 97 6.1 Abordagens de teste para sistemas sensíveis ao contexto . . . . . . . . . p. 97 6.2 Análise de abordagens existentes . . . . . . . . . . . . . . . . . . . . . p. 101 6.3 Técnicas de teste para sistemas embarcados . . . . . . . . . . . . . . . p. 103 6.4 Ferramentas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 104 7 Conclusões p. 105 7.1 Limitações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 106 7.2 Trabalhos futuros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . p. 107 Referências p. 109 Apêndice A -- Script do sistema de trava automática por detecção de código de batidas p. 112 14 1 Introdução Sistemas embarcados dependentes do contexto no qual estão inseridos, como por exem- plo detectores de fumaça ou sistemas de iluminação automática nas escadas de um prédio, podem ser visualizados como um loop que continuamente coleta dados de sensores, trans- forma estes dados em informação útil e faz uso desta informação útil para determinar seu comportamento (Figura 1). Essa informação útil pode ser gerada através de uma única iteração deste loop, mas, muitas vezes, é resultado da combinação de seguidas iterações de seu loop principal. Figura 1: Representação do loop de execução de um sistema dependente do contexto Para exemplificar melhor esses dois casos, imaginemos primeiro um sistema desen- volvido para o microcontrolador Arduino, capaz de detectar movimentação nas escadas de um prédio e acender as luzes do ambiente, caso haja alguém. O código na Figura 2 representa de forma simplificada o loop principal desse sistema. Uma simples leitura digital de um sensor de movimento PIR, recebida pelo Arduino como 0 ou 1, irá determinar se a lâmpada deve acender ou não. Isto é, uma única iteração no loop principal do sistema é o suficiente para determinar um comportamento que pode ser testado e a etapa de tradução dos dados do sensor (0, 1) em informação útil (nenhuma 15 Figura 2: Loop principal do sistema de iluminação automática movimentação detectada, movimentação detectada) é tão direta que está implícita no código. Este tipo de sistema é simples de ser testado, visto que uma simples refatoração (Fi- gura 3) pode isolar em um único método o comportamento esperado pelos testes (acen- der ou apagar as luzes) de acordo com o contexto (a leitura do sensor, passada como parâmetro). A funcionalidade principal do sistema pode então ser testada por uma ferra- menta que auxilie a criação de testes de unidade, como o AUnit, exercitando o método analisar(int leitura) para as duas possíveis entradas (0 e 1) e suas saídas espe- radas (chamadas dos métodos acenderLampada() ou apagarLampada()). Figura 3: Refatoração do código para facilitar a criação de testes de unidade Apesar de efetiva, esta solução pode não ser o suficiente para sistemas um pouco mais complexos, cujo comportamento é baseado no resultado de várias iterações do loop principal. Para ilustrar este outro cenário, imaginemos agora um sistema que destrava uma porta através de um “código secreto” de batidas. As batidas são percebidas por um elemento piezo, enquanto que um módulo relé é utilizado para ativar ou desativar uma fechadura elétrica. A cada iteração do loop, que dura aproximadamente 10ms, o Arduino faz uma leitura analógica ao elemento piezo, que retorna um inteiro entre 0 e 1023, representando a intensidade da batida detectada. 16 Identificar batidas individuais é simples, entretanto, para detectar o “código secreto” esse sistema deve ser capaz de ignorar possíveis ruídos nas leituras, levar em consideração o intervalo de tempo entre cada batida detectada e, claro, acompanhar o se as batidas realizadas até o momento seguem o ritmo definido pelo código secreto. Isto é, não apenas dependente dos dados de contexto, este sistema é dependente do contexto de forma sensível ao tempo. Podemos perceber também que a tradução dos dados do sensor (inteiros de 0 a 1023) em informação útil (o padrão de batidas performado) não é implícita - muito pelo contrário, são necessárias várias variáveis que acompanhem intervalos entre batidas, detecção de ruídos, dentre outros detalhes necessários para realizar esta tradução de dados crus em informação útil. Tendo em vista essas características do sistema, podemos notar que é impossível isolar o comportamento do sistema em um único método, para que este seja testado por testes de unidade. Surge então a pergunta: Como podemos testar este tipo de sistema? 1.1 Limitações das abordagens atuais Atualmente, existem algumas ferramentas desenvolvidas com o propósito de auxiliar a atividade de testes de sistemas desenvolvidos em Arduino. O AUnit, por exemplo, é uma ferramenta criada para auxiliar a criação de testes de unidade para tais sistemas. Entretanto, quando o comportamento que queremos testar é resultado de diversas itera- ções do seu loop principal - e mais ainda quando o sistema também é sensível ao tempo - saímos da ideia de “testes de unidade”, que cobrem um método específico, e avançamos em direção à ideia de “testes de sistema”, pois todo o sistema precisa ser executado para obtermos o comportamento desejado para o teste. Além disso, o AUnit não oferece nenhum suporte à simulação de sensores (o que impossibilita a automação de testes baseados no contexto) e os testes criados por esta fer- ramenta rodam diretamente no Arduino, ocupando espaço na sua memória. Dessa forma, quanto mais testes forem criados, mais memória é utilizada no Arduino, de modo que existirá um limite no volume (número e tamanho) dos testes. Atualmente, para o conhecimento do autor, não existe nenhuma ferramenta que auxilie a criação de testes para sistemas reativos desenvolvidos em Arduino. que ofereça suporte à simulação de contexto de forma sensível ao tempo. 17 1.2 Solução proposta Para que a atividade de testes seja eficiente, escalando conforme o sistema evolui sem o risco de chegar ao ponto em que toda a memória do Arduino é consumida e não possamos adicionar novos testes, é importante que a implementação dos testes seja feita de forma independente do microcontrolador, em um outro ambiente. Ao mesmo tempo, não é interessante utilizar emuladores para executar o sistema sob testes completamente em um computador, visto que possíveis erros decorrentes de limitações do hardware alvo do sistemapodem não ser capturados pelos testes sendo executados no emulador. A solução proposta por este trabalho resolve este impasse: os testes devem ser definidos a partir de um framework, em Java, em um computador conectado ao Arduino, que por sua vez, executa simultaneamente o sistema sob testes, de modo que ambos se comuniquem em tempo de execução para que sejam acompanhadas as condições de sucesso ou falha dos testes e também para que dados de contexto (leituras a sensores) sejam simulados, permitindo a automação dos testes. Essa solução não ocupa tanto espaço na memória do Arduino, apenas o suficiente para estabelecer a comunicação Arduino-computador. Desta forma, mais testes podem ser adicionados sem a preocupação de lotar a memória do microcontrolador. Além disso, por serem desenvolvidos em Java, os testes podem ser integrados ao JUnit, uma poderosa ferramenta de automação de testes, que irá facilitar o monitoramento dos resultados dos testes, oferecendo feedback visual dos resultados e apontando onde ocorreram falhas ou erros de forma simples e eficiente. 1.3 Objetivos O principal foco deste trabalho é o desenvolvimento do frameworkConBaT (Context- Based Testing), que tem como objetivo auxiliar a atividade de testes em sistemas desenvol- vidos para Arduino. O framework dá suporte à criação e execução de testes dependentes do contexto e de forma sensível ao tempo. Como sistemas dependentes do contexto têm seu comportamento ditado pelas varia- ções do contexto no qual está inserido, este trabalho traz também como contribuição uma abordagem para documentação das variações de dados de contexto, em arquivos chamados context files. Estes arquivos, além de armazenar dados de sensores, carregam informações 18 detalhadas sobre os sensores utilizados, além de características da coleta, como duração total, intervalo entre capturas de dados, etc. O ConBaT utiliza estes arquivos como entrada para seus testes e também oferece a funcionalidade de coletar dados de contexto e gerar context files bem documentados. 1.4 Organização do texto Além deste capítulo de introdução, este trabalho apresenta mais 6 capítulos. O capí- tulo 2 apresenta a fundamentação teórica relacionada à criação deste trabalho. O capítulo 3 está relacionado à abordagem de testes proposta, apresentando o conceito de context files e seu uso como entrada para testes baseados em contexto. O capítulo 4 apresenta o framework ConBaT e detalhes sobre o seu funcionamento. O capítulo 5 tem como objetivo a avaliação da ferramenta ConBaT. O capítulo 6 apresenta trabalhos - artigos e ferramentas - relacionados à abordagem proposta por este trabalho. Por fim, o capítulo 7 aponta as contribuições deste trabalho, limitações encontradas e trabalhos futuros. 19 2 Fundamentação Teórica Este capítulo aborda conceitos necessários para a compreensão do trabalho. Primei- ramente são apresentados os conceitos de contexto e sistemas sensíveis ao contexto. Em seguida, são apresentadas as definições de sistemas embarcados e ubíquos, seguidas pela apresentação do Arduino, plataforma à qual o framework desenvolvido por esse projeto está relacionado. As seções seguintes falam sobre teste de software, automação de testes e, por fim, da ferramenta JUnit. 2.1 Contexto Muitas definições de contexto foram propostas ao longo dos anos. A introdução do termo context-aware foi feita pelo trabalho de (SCHILIT; THEIMER, 1994), em que contexto significa localização, identidades de pessoas e objetos próximos e mudanças relacionadas a esses objetos. Em uma definição similar, (BROWN, 1998) define contexto como localização, identidades de pessoas em volta do usuário, o período do dia, estação do ano, tempera- tura, etc. (RYAN; PASCOE; MORSE, 1997) definem contexto como a localização do usuário, ambiente, identidade e tempo. (DEY, 1998) enumera contexto como o estado emocional do usuário, foco de atenção, localização e orientação, dia e hora, objetos e pessoas no ambiente do usuário. Outras definições trazem apenas sinônimos de contexto, como o ambiente ou situação. Alguns autores consideram informações sobre o ambiente em que o usuário está, outros, em que a aplicação está. A definição adotada por este trabalho é a de (ABOWD et al., 1999), que define contexto como qualquer informação que possa ser utilizada para caracterizar a situação de uma entidade. Uma entidade pode ser compreendida como uma pessoa, um lugar ou um objeto considerado relevante para a interação entre um usuário e a aplicação. É comum acreditar que o contexto consiste apenas de informação implícita, porém 20 esta definição também engloba informações explicitamente fornecidas pelo usuário. Por exemplo, a identidade do usuário fará parte do contexto quer ela tenha sido obtida im- plicitamente, por exemplo por reconhecimento facial, quer explicitamente, através de um login. O trabalho de (ABOWD et al., 1999) também apresenta como tipos primários de con- texto: localização, identidade, atividades e tempo. Eles não respondem diretamente às perguntas “quem”, “o quê”, “quando” e “onde”, mas funcionam como índices para outras fontes de informação. Todos os outros tipos de informações de contexto são derivados desses tipos primários. 2.2 Sistemas sensíveis ao contexto De forma similar à definição de contexto, há muitos trabalhos que tentam definir o que são sistemas cientes do contexto, ou sensíveis ao contexto. A definição adotada por este trabalho também é a de (ABOWD et al., 1999): um sistema é sensível ao contexto se ele faz uso do contexto para prover informações e/ou serviços relevantes ao usuário, de modo que a relevância depende da tarefa sendo executada pelo usuário. As funcionalidades de sistemas sensíveis ao contexto podem ser categorizadas em três grupos (ABOWD et al., 1999): • Apresentação de informações e serviços ao usuário; • Execução automática de um serviço; • Associação de contexto a informações a serem utilizadas posteriormente. 2.3 Sistemas embarcados Sistemas embarcados (ou sistemas embutidos), são sistemas computacionais completos e independentes, focados em executar uma determinada função, geralmente em um loop infinito. Comparado a um computador pessoal, sistemas embarcados apresentam os mesmos componentes, porém com tamanho e capacidade limitadas. Devido às suas limitações, a maioria dos usuários não os consideram computadores. 21 O desenvolvimento do software utilizado em um sistema embarcado normalmente é feito em um computador comum e transferido para o sistema embarcado apenas nos estágios finais do desenvolvimento. Em alguns casos, como nos sistemas embarcados de- senvolvidos em Arduino, essa transferência é feita através da porta USB. 2.4 Arduino Arduino é uma plataforma de eletrônicos open-source baseada em software e hardware de fácil uso. Placas Arduino são capazes de receber entradas - temperatura do ambiente capturada por um sensor, toque em um botão, ou mesmo uma mensagem do Twitter - e transformá-las em saídas - ativação de um motor, iluminação de um LED, publicação de algo online. De forma genérica, sensores são responsáveis pela obtenção da entrada de dados no sistema, enquanto que atuadores são os meios pelos quais o microcontrolador manifesta saídas, como ilustrado pela Figura 4. O microcontrolador presente na placa recebe instruções por meio da linguagem de programação Arduino (baseada na Wiring) e do Arduino Software (IDE), baseado no Processing. Figura 4: Visão geral dos componentes de um sistema desenvolvido para Arduino O Arduino é usado como o cérebro de diversos tipos de projetos, desde objetos do dia-a-dia a instrumentos científicos complexos. Uma comunidade global de criadores - estudantes, hobbistas, artistas, programadores e profissionais - têm se juntado em torno dessa plataforma open-source. Há muitos outros microcontroladores e plataformas de microcontroladores disponíveis que oreferecem funcionaidades similaridas, como o Parallax Basic Stamp, BX-24da Net- Media, Phidgets, Handyboard do MIT, dentre outros. Todas essas ferramentas encapsulam detalhes complicados de programação para microcontroladores em um pacote simples, de fácil uso. Arduino também simplifica o processo de trabalhar com microcontroladores, mas também oferece vantagens adicionais: 22 • É barato - a versão mais barata pode ser montada à mão e os pré-montados custam menos de 50 USD; • Multiplataforma - o Arduino Software (IDE) roda no Windows, Macintosh OSX e Linux. A maioria dos sistemas microcontroladores é limitado ao Windows; • Ambiente de programação simples e claro - a IDE é simples para iniciantes e flexível o suficiente para usuários avançados. Para professores, é convenientemente baseado no ambiente de programação Processing; • Software open-source e extensível - O código é aberto e disponível para extensão por programadores experientes. A linguagem pode ser expandida através de bibliotecas C++ e pessoas que querem entender detalhes técnicos podem pular do Arduino à linguagem de programação AVR-C, na qual o Arduino é baseado. Também é possível adicionar código AVR-C diretamente em programas Arduino; • Hardware open-source e extensível - os projetos das placas Arduino são publicados sob uma licença Creative Commons. Logo, designers de circuito experientes podem fazer sua própria versão do módulo, estendendo-o e melhorando-o. Até mesmo usuá- rios relativamente inexperientes podem construir a versão breadboard do módulo para compreender como ele funciona e economizar dinheiro. Há três tipos de memória nas placas Arduino: (i) a memória flash, que armazena o programa em si; (ii) a SRAM, onde são criadas e manipuladas variáveis em tempo de execução e (iii) EEPROM, que é a memória que os programadores podem usar para armazenar informações persistentes, isto é, que não serão perdidas caso o Arudino seja reiniciado. A quantidade de memória flash, SRAM e EEPROM encontrada nos chips ATmega328P e ATmega2560, utilizados nas placas Uno e Mega2560, respecticamente, são encontradas na Tabela 1. Tabela 1: Memória disponível em diferentes chips utilizados por placas Arduino. Flash SRAM EEPROM ATmega328P 32k bytes 2k bytes 1k bytes ATmega2560 256k bytes 8k bytes 4k bytes 2.5 Sistemas Reativos Sistemas reativos são sistemas responsivos, conduzidos por mensagens, resilientes (to- lerantes a erros) e elásticos (se mantém responsivos reagindo a mudanças no ritmo de 23 acesso). Muitos dos projetos desenvolvidos para Arduino são sistemas reativos, que pas- sam a maior parte do tempo monitorando informações, como dados de contexto, e reagindo quando algum estímulo esperado é identificado. 2.6 Teste de software O objetivo do teste de software é encontrar falhas em um produto, de modo que as causas dessas falhas possam ser identificadas e possíveis erros de código possam ser conser- tados antes da entrega do software. Sendo assim, é uma atividade de grande importância para fornecer confiança de que o sistema irá funcionar como esperado em seu ambiente de uso. Devido ao seu foco em buscar e expor problemas, podemos dizer que a atividade de teste é “destrutiva” (NETO, 2007). 2.6.1 Conceitos básicos Para compreender a atividade de teste de software em mais detalhes é necessário conhecer os conceitos de defeito, erro e falha. Segundo a terminologia para Engenharia de Software do IEEE, defeito é um ato inconsistente cometido por um indivíduo ao tentar entender uma determinada informação, resolver um problema ou utilizar um método ou uma ferramenta; erro é a manifestação concreta de um defeito no artefato de software; e falha é o comportamento operacional do software diferente do esperado pelo usuário. Erros podem ou não levar a falhas. O objetivo do teste de software é revelar falhas para que, através de uma depuração, os erros que as causaram sejam corrigidos. Alguns outros conceitos importantes são os de caso de teste, procedimento de teste e critérios de teste. Casos de teste consideram uma situação ou parte do código a ser testada e, a partir disso, definem valores de entrada, restrições e resultado esperado após a execução do código. O procedimento de teste é a descrição dos passos necessários para executar um caso de teste. Os critérios de teste, por sua vez, são usados para selecionar e avaliar os casos de teste, podendo ser: funcionais, estruturais e baseados em defeitos. 2.6.2 Níveis de teste e o modelo V Não importa a tecnologia utilizada, os defeitos são causados por humanos e estarão sempre presentes no desenvolvimento de um sistema, desde as primeiras fases. Para pro- curar por falhas e eliminar erros desde o início, onde o custo de reparo é menor, existem 24 diferentes níveis de teste: • Testes de unidade são responsáveis por testar métodos e pequenos trechos de código; • Testes de integração testam a comunicação ou interface entre diferentes módulos; • Testes de sistema buscam verificar se o software satisfaz os requisitos especificados, sendo realizados no sistema como este seria utilizado pelo usuário final; • Testes de aceitação são realizados por um grupo de usuários finais do sistema, com o objetivo de verificar se o sistema realmente funciona como esperado pelos usuários; • Testes de regressão não são exatamente uma categoria de nível de testes e estão relacionados à repetição de testes já realizados a cada nova versão ou ciclo do soft- ware. Figura 5: Modelo V proposto por Craig e Jaskiel, 2002 É recomendado que o planejamento e projeto dos testes ocorra “de cima para baixo”: primeiro são criados os casos de teste de aceitação juntamente à elicitação de requisitos; depois os testes de sistema são criados, juntamente com o projeto de alto nível; depois vêm os testes de integração, com o projeto detalhado e, finalmente, os de unidade quando o código começa a ser implementado. A execução dos testes então acontece na ordem inversa, dos testes de unidade aos de aceitação. 2.6.3 Atividades de Teste (FEWSTER; GRAHAM, 1999) descrevem cinco atividades necessárias para se testar um sistema, que são: 25 • Identificação de condições de teste (itens ou eventos a serem testados) e priorização; • Criação dos casos de teste: definição dos dados de entrada e saída esperada; • Implementação dos casos de teste; • Execução dos testes; • Comparação da saída obtida com o resultado esperado. As duas primeiras etapas, que envolvem uma análise do que será testado e o design de casos de teste, são geralmente realizadas apenas uma vez e exigem mais criatividade. As demais atividades, relacionadas à implementação, execução dos testes e checagem de resultados são mais mecânicas e geralmente acontecem repetidas vezes durante o desen- volvimento do sistema. 2.6.4 Critérios de teste Segundo (FEWSTER; GRAHAM, 1999), testar é uma habilidade. Há um número as- tronômico de possibilidades de casos de teste para um sistema, porém um tempo limitado suficiente para executar apenas uma pequena parcela. Dessa forma, os casos de teste não podem ser definidos arbitrariamente, sendo necessários assim critérios de teste. Esses cri- térios são utilizados para selecionar um grupo de valores de entrada que representa bem o conjunto de possíveis entradas do sistema, com o objetivo de encontrar o maior número de defeitos possível. Os critérios de teste se dividem em três tipos: estruturais, funcionais e baseados em defeitos. 2.6.4.1 Critérios estruturais Para testes que fazem uso de critérios estruturais, também conhecidos como testes caixa-branca, a estrutura do componente de software a ser testado é considerada, de modo que podemos saber que linhas de código estão ou não sendo executadas em cada caso de teste. Esses testes são melhor projetados e executados pelos próprios desenvolvedores, nos níveis de unidade e integração, por conhecerem melhor o código. O grafo de causa-efeito é um exemplo de critério estrutural, que considera as causas (condições de entrada) e os efeitos (ações relacionadas às diferentescondições de entrada) para construir um grafo a partir do qual é criada uma tabela de decisão. Dessa tabela de decisão serão extraídos os casos de teste. 26 2.6.4.2 Critérios funcionais Testes criados a partir de critérios funcionais, por outro lado, abordam o componente a ser testado como uma caixa-preta - não importa o funcionamento, o que importa é se a saída obtida é igual à saída esperada para a entrada fornecida. Os testes funcionais podem ser executados para todos os níveis de teste. Existe também o conceito de testes “caixa-cinza”, que são testes funcionais que ne- cessitam de um certo conhecimento da estrutura do código (como nome de métodos ou variáveis) para ser realizado. O particionamento em classes de equivalência é um critério funcional que usa o con- ceito de classes de equivalência para selecionar as entradas dos testes. Espera-se que entradas que fazem parte da mesma classe de equivalência se comportem de maneira equivalente - assim, em teoria, basta que seja criado um caso de teste para cada classe. Por exemplo, se um sistema que realiza empréstimos aplica uma taxa de juros diferente para (i) empréstimos abaixo de 1.000 reais, (ii) acima ou igual a 1.000 e abaixo de 10.000 reais e (iii) de 10.000 reais para cima, temos nessa situação três classes de equivalência. É importante também separar classes de equivalência para entradas válidas e inválidas. A análise do valor limite é um outro critério bastante utilizado, pois a maioria dos erros tende a ocorrer nos limites do domínio de entrada. Se nosso domínio de entrada é a faixa de valores limitada entre a e b, por exemplo, esse critério considera como entradas importantes para os casos de teste os valores próximos aos limites, ou seja, o valor de a, de b, e os valores imediatamente acima e abaixo de a e de b. Por exemplo, se um certo campo aceita valores numéricos entre 0 e 10, devemos criar pelo menos casos de teste com os valores de entrada -1, 0, 1, 9, 10 e 11. Esse critério não se aplica apenas a entradas numéricas. Pode, por exemplo, se aplicar ao tamanho de uma senha. Se o sistema exige que a senha digitada tenha de 3 a 6 dígitos, é interessante criar casos de teste com senhas de 2, 3, 6 e 7 dígitos 2.6.4.3 Critérios baseados em defeitos Testes criados com base em defeitos, como o próprio nome sugere, são testes estabe- lecidos com base nos defeitos comuns cometidos durante o desenvolvimento do software. Um exemplo de uso desse critério são os testes de mutação. Esse tipo de teste cria uma cópia do programa com uma pequena mutação (por exemplo, a substituição do operador “menor que” pelo “menor ou igual”, ou de um laço “while” por um “do-while”). É esperado 27 que o conjunto de testes criado para o software detecte essa alteração e pelo menos algum falhe. Caso nenhum teste falhe, é necessário “matar” este mutante - isto é, criar um caso de teste que cause sua falha. 2.6.5 Objetos mock Objetos mock são objetos criados para simular o comportamento de objetos reais com o objetivo de se testar alguma outra parte do sistema, que depende desta parte sendo “mockada”. É uma técnica muito utilizada em Test Driven Development (FREEMAN; PRYCE, 2009), pois permite que os desenvolvedores foquem seus testes no comportamento do sistema sob testes, sem se preocupar com suas dependências. • Criar um objeto mock pode ser útil nas situações em que o objeto a ser mockado: • Fornece resultados não-determinísticos (como a temperatura ou hora atual); • Tem estados difíceis de se criar ou reproduzir (como um erro de rede); • É lento (como um banco de dados completo, que demoraria muito para ser iniciali- zado antes do teste); • Ainda não existe ou pode ter seu comportamento alterado; • Teria que incluir informação e métodos exclusivamente para testes (e não para sua real função). 2.7 Automação de testes Automatizar testes envolve a utilização de softwares, ou ferramentas de automação, para controlar uma ou mais atividades de teste, aumentando assim a produtividade e reduzindo custos. Segundo (FEWSTER; GRAHAM, 1999), “em um bom regime de automação de testes, os testes são fáceis de serem executados, são autossuficientes e é mais fácil adicionar um novo teste automatizado do que executar o mesmo teste manualmente”. Dentre as vantagens da automação de testes, podemos citar: • Execução automática de testes de regressão, isto é, testes executados repetidas vezes durante a evolução de um sistema; 28 • Execução de mais testes mais frequentemente; • Possibilidade de performar testes que seriam difíceis ou impossíveis de serem reali- zados manualmente; • Melhor utilização de recursos - testadores podem focar em criar testes melhores em vez de perder tempo com tarefas repetitivas (e passíveis de erro humano) de testes manuais; • A repetição de um mesmo caso de testes é consistente; • Testes podem ser reutilizados; • Conclusão mais rápida do projeto; • Aumento na confiança. Apesar de apresentar muitas vantagens, é importante lembrar que testes ruins, após automação, continuam sendo testes ruins. Dessa forma, a automação pode causar altas expectativas não-realistas e transmitir um falso senso de segurança, caso a prática com testes seja precária. Testes manuais ainda costumam encontrar mais defeitos (cerca de 85% mais), pois o testador humano faz constantes checagens, algumas conscientemente e provavelmente muitas inconscientemente. Testes automatizados verificam apenas o que eles foram pro- gramados para verificar. Desta forma, dependendo do sistema a ser testado, da qualidade dos testes criados e do processo de automação empregado, é necessário tomar cuidado para que a automação não afete negativamente o desenvolvimento do software. (FEWSTER; GRAHAM, 1999) afirmam que a automação não vale a pena quando: • Testes são raramente executados; • O software é muito volátil; • O resultado é facilmente verificado por humano, mas difícil ou impossível de se automatizar; • Os testes envolvem interação física. 29 Mesmo que a automação seja viável para o sistema em questão, o esforço exigido para implementá-la irá depender de alguns fatores. Automatizar um caso de teste pode levar de 2 a 30 vezes mais tempo que sua execução manual levaria. Dentre os fatores que influenciam o esforço de automação, pode-se citar: • Ferramenta utilizada; • A abordagem utilizada - por exemplo, gravação e reprodução de uma execução manual; • O nível de experiência do automador; • O ambiente de execução, que pode ser difícil de replicar; • O software sob testes: quanto menor for a interação com o usuário, mais fácil será a automação; • O processo de testes existente, que pode ser: – Ad hoc: não segue nenhum script, segue a ideia de “não há tempo de documen- tar, apenas teste!”; – Scripts manuais vagos: segue scripts que dão instruções alto nível de execução; – Scripts manuais detalhados: segue scripts detalhados, que incluem cada instru- ção básica de interação com o sistema. Esses scripts podem ser mais facilmente convertidos em scripts de execução automatizada. 2.7.1 Capture replay e automação Quando falamos em automação da atividade de teste de software, estamos falando em automatizar uma ou mais das atividades de teste, descritas anteriormente (análise, design de casos de teste, implementação, execução e comparação de resultados). A técnica de capture replay (FEWSTER; GRAHAM, 1999) consiste em gravar a interação do testador com o sistema, de modo que essa gravação possa ser usada para execução do sistema automaticamente. Dessa forma, ela automatiza a atividade de execução dos testes. Como benefícios dessa técnica, podemos citar: • Capturar e gravar inputs gera de certa forma uma documentação automática dos testes executados; 30 • Testes podem ser reproduzidos com mais precisão e mais rapidamente; • Gravações também podem ser utilizadas para fazer as mudanças de manutenção em massa; • Podem ser reutilizadas em sistemas multi-plataforma com poucas alterações;• Permite reprodução de bugs, também para checar se já foram corrigidos. Não podemos, entretanto, confundir a simples atividade de capture replay com au- tomação de testes, pois a atividade de testes final, que é a comparação dos resultados obtidos com os resultados esperados, não é incluída nesse processo. Os resultados espera- dos nem mesmo são definidos - a reprodução da gravação apenas tem a ver com entradas utilizadas e execução automática do sistema. Dentre outras desvantagens da utilização de capture replay, podemos citar o forte acoplamento entre a gravação e a versão atual do sistema utilizada para a gravação. Quando o software é alterado, alterar o script pode dar até mais trabalho do que fazer uma nova gravação. Um script de gravação “cru” também não explica nada sobre o que está sendo testado ou qual o propósito do teste, e pode ser muito difícil de se compreender, quando consultado novamente no futuro. 2.7.2 Técnicas de scripting Scripts são a base da automação de testes, pois são arquivos que carregam informações do que será automatizado e como será automatizado. De acordo com Fewster e Graham (FEWSTER; GRAHAM, 1999), eles podem ser: • Scripts lineares - bons para ações repetitivas, demonstrações, treinamentos, para automatizar set-ups e clear-ups para testes, popular um arquivo ou banco de dados. São mais vulneráveis a mudanças e difíceis de serem atualizados. Scripts lineares de teste contém as entradas e a saída esperada e esse forte acoplamento faz com que cada novo teste leve tanto trabalho para ser automatizado quanto o primeiro; • Scripts estruturados - Usam as estruturas de controle “sequência”, “seleção” e “ite- ração”. Podem chamar um outro script durante a sua execução. São mais robustos por possibilitarem a separação de responsabilidades diferentes em scripts diferentes; • Scripts compartilhados - são usados por mais de um caso de teste, diminuindo custos de manutenção e esforço para implementar testes similares; 31 • Scripts orientados a dados - dados de entrada são armazenados em um único arquivo separado, enquanto o script fica apenas com informações de controle. Dessa forma, fica muito fácil e rápido adicionar novos casos de teste, mas a criação do primeiro exige tempo, esforço e conhecimento técnico para programá-lo. O esforço, entretanto, é rapidamente recompensado quando há centenas ou milhares de testes; • Scripts orientados a palavras-chave - combina a técnica orientada a dados com o desejo de especificar testes automatizados sem precisar entrar em detalhes de execução. Arquivos de teste descrevem o que o teste faz através de palavras-chave e não como o faz. Um script de controle irá ler essas palavras-chave e chamar scripts responsáveis por cada ação. Podemos citar como vantagens desse tipo de script: – O número de scripts é baseado no tamanho do software e não no número de testes, reduzindo custos de manutenção; – Acelera a implementação e automação de novos testes; – Permite que não-programadores criem casos de teste; – Testes podem ser implementados independentemente da ferramenta ou plata- forma. Para que scripts possam ser facilmente compreendidos por humanos e melhor utili- zados pelas ferramentas de automação, é importante seguir algumas boas práticas. Bons scripts devem ser: • Comentados, para guiar usuário e responsáveis pela manutenção; • Funcionais, executando uma única tarefa, encorajando o reuso; • Estruturados, para facilitar a leitura, compreensão e manutenção; • Fáceis de se compreender; • Documentados, informando seu propósito, incluindo referências a scripts similares que podem ser afetados caso haja uma alteração. Um pré-processamento de scripts pode melhorar a forma como ele foi escrito, o ade- quando melhor às boas práticas mencionadas anteriormente. Beautifiers são ferramentas que checam o layout e formatação dos scripts, fazendo ajustes, se necessário, para confor- mação a algum padrão. Algumas ferramentas de análise estática ajudam a capturar erros 32 que ferramentas de automação podem deixar passar por estar sintaticamente correto. Por fim, podem ser feitas substituições gerais, por exemplo, de códigos longos ou difíceis de se entender por algo mais simples e direto. 2.7.3 Automação da comparação de resultados Como mencionado anteriormente, a técnica de capture replay não oferece nenhum suporte à comparação de resultados, que é a atividade final do teste, responsável por determinar se o teste passou ou não. Para realizarmos uma comparação de resultados, precisamos primeiro definir o que será comparado. (FEWSTER; GRAHAM, 1999) definem as seguintes categorias de saídas: • Saídas baseadas em disco: arquivos de texto, capturas de tela na forma de caracteres, comparação de bancos de dado e arquivos binários; • Saídas baseadas na tela: aplicações baseadas em caracteres, aplicações GUI (se pos- sível, fazer comparações antes da conversão em bitmap); • Saídas multimídia: nesse caso, é interessante aprimorar a aplicação sob teste para que ela dê ao testador acesso a um nível útil de informação; • Comunicação entre aplicações: pode ser necessário um simulador para as demais aplicações envolvidas, capaz de mandar e/ou receber mensagens do software sob teste. A comparação pode ser dinâmica, isto é, performada durante a execução do caso de teste, ou pós-execução. A comparação dinâmica ajuda o teste a tomar decisões durante a execução, podendo até mesmo ser encerrado prematuramente, caso algo errado seja detectado em tempo de execução. Já a comparação pós-execução, por ser realizada após execução do teste, pode ser realizada offline a qualquer momento, até mesmo em uma má- quina diferente de onde os testes foram executados. A comparação pós-execução também pode utilizar diferentes comparadores, enquanto que a dinâmica se encontra fortemente atrelada à ferramenta utilizada. Filtros de comparação podem ser utilizados para transformar as saídas obtidas e esperadas em um formato que facilite a comparação, por exemplo, em arquivos de texto. Há uma grande disponibilidade de ferramentas de manipulação de texto e a comparação se torna de fácil implementação e debug - ferramentas de comparação simples podem performar comparações complexas. 33 2.7.4 Métricas O uso de métricas em testes e automação de testes é importante, pois podem ser utilizadas para avaliar escolhas, comparar alternativas, monitorar melhorias, prever pro- blemas, servir de referência para comparação com padrões, com a concorrência ou, de modo geral, analisar o retorno no investimento. Ao longo do desenvolvimento de software, muitas características podem ser medidas, como por exemplo: • Linhas de código; • Pontos de função; • Bytes de código de objetos; • Número de decisões; • Custo de implementação; • Número de defeitos encontrados; • Número de desenvolvedores; • Número de scripts de automação; • Número de testes automatizados; • Tempo de execução dos testes automatizados; • Tempo ou esforço de manutenção dos testes; • Número de testes que falharam devido a defeitos; • Número de testes numa suíte de testes; • Número de testes planejados, executados e que passaram ou falharam; • Custo com atividades de teste; • Número de defeitos encontrados em testes e em uso real; • Cobertura de código por parte dos testes; 34 A Lei de Gilb (GILB, 1988) diz que “tudo pode ser medido de alguma forma, e que ter conhecimento dessa medida é superior a não ter medida alguma”. (HETZEL, 1993) define que uma métrica é importante se ela pode ser obtida de forma relativamente fácil e utilizada em uma atividade de análise e tomada de decisões efetivamente. As seções seguintes apresentam alguns atributos do processo de automação de testes que podem ser medidos. 2.7.4.1 Manutenibilidade Manutenibilidade está relacionada à facilidade de manter os testes atualizados após alterações no sistema. Esse atributo pode se medido através de: • Média de tempo passado (tempo total) ou esforço (horas detrabalho) para se atu- alizar cada teste; • Frequência de ocorrência de mudanças no software, que podem ser: – Mudanças na interface; – Mudanças nas regras de negócio; – Mudanças no formato de arquivos ou banco de dados; – Mudanças no conteúdo de um relatório; – Mudanças no protocolo de comunicação; – Mudanças simples/complexas nas funcionalidades; 2.7.4.2 Eficiência A eficiência está relacionada a custos e é uma das principais razões pelas quais auto- mação de testes é requisitada. O dicionário define eficiência como "funcionar ou produzir efetivamente e com o menor esforço possível". Eficiência pode ser medida através de: • Porcentagem de scripts que foram usados pelo menos X vezes; • Tempo e/ou esforço necessário para realizar tarefas, como: – Adicionar um novo conjunto de testes automatizados; – Realizar set-up e clean-up após a execução de um conjunto de casos de teste; 35 – Selecionar um subconjunto de casos de teste para ser executado; – Executar um conjunto de casos de teste automatizados; – Monitorar, se necessário, a execução dos testes automatizados; – Comparar resultados para definir o resultado do teste; – Debugar os testes automatizados. 2.7.4.3 Confiabilidade A confiabilidade está relacionada à habilidade de fornecer resultados precisos e repe- tíveis. Esse atributo pode ser medido através de: • Porcentagem de testes que falharam devido a defeitos nos próprios testes (seja no design dos testes ou na atividade de automação; • Número de ciclos de testes ou iterações adicionais necessárias quando defeitos são encontrados nos testes; • Número de falsos negativos: testes que falharam, apesar de o sistema ter se compor- tado corretamente; • Número de falsos positivos: testes que passaram, ignorando defeitos que deveriam ter sido detectados. 2.7.4.4 Flexibilidade Flexibilidade está relacionada ao quão flexível o regime de automação é para ser manipulado de alguma forma, por exemplo, permitir combinação de diferentes testes ou filtrar testes concluídos de acordo com parâmetros específicos. Pode ser medido por: • Tempo necessário para se testar uma correção de emergência em uma versão antiga; • Tempo necessário para identificar um conjunto de casos de teste com algum objetivo. Por exemplo, todos os testes que falharam na última vez em que foram executados • O número de critérios de seleção que podem ser utilizados para identificar um sub- conjunto de casos de teste; • Tempo e/ou esforço necessários para restaurar um caso de teste que tenha sido arquivado. 36 2.7.4.5 Usabilidade O atributo usabilidade está relacionado ao quão fácil é se utilizar o regime de auto- mação existente e pode ser medido através de: • Tempo necessário para adicionar N novos casos de teste similares a um regime existente; • Tempo ou esforço necessários para verificar os resultados dos testes; • Tempo de treinamento necessário para um usuário do regime se tornar confiante e produtivo; • Tempo ou esforço necessários para descartar defeitos que não são de interesse para um conjunto de casos de teste. Por exemplo, um pequeno defeito que não será corrigido até uma próxima versão; • As percepções dos usuários do regime sobre o quão fácil é utilizar o regime e o quanto eles gostam do regime atual. Pode ser medido através de surveys. 2.7.4.6 Robustez Referente ao quão útil a automação de testes é em sistemas voláteis, podemos medir a robustez através de: • Número de testes que falham devido a um único defeito no software; • O quão frequentemente um teste automatizado falha devido a eventos inesperados ou o número ou porcentagem de testes que falham devido ao mesmo evento inesperado ou a porcentagem de testes que falham devido a eventos inesperados comparado ao número de defeitos únicos encontrados por aquele conjunto de testes; • O tempo médio que leva desde o início de um teste até um evento inesperado causar sua falha; • O tempo necessário para investigar as causas de eventos inesperados que causam a falha de testes. 37 2.7.4.7 Portabilidade Portabilidade tem a ver com a habilidade do regime de automação ser executado em diferentes ambientes. Pode ser medido através de: • Tempo ou esforço necessários para fazer um conjunto de testes automatizados ro- darem com sucesso em um novo ambiente (por exemplo, uma nova base de dados) ou em uma nova plataforma de hardware; • Tempo ou esforço necessários para fazer um conjunto de testes automatizados ro- darem utilizando uma ferramenta de testes diferente; • Número de diferentes ambientes em que os testes automatizados podem ser execu- tados. 2.8 JUnit O JUnit é um framework open-source, criado por Erich Gamma e Kent Beck, que oferece suporte à criação de testes automatizados na linguagem de programação Java. Tem sido também importante para a consolidação do Test Driven Development (TDD), pois permite uma rápida criação de código de teste e, além de muito poderoso, é também muito simples de ser utilizado. O JUnit, como o próprio nome sugere, apoia a criação de testes de unidade, que exer- citam pequenos trechos de código. Esses testes são definidos por entradas (por exemplo, parâmetros para um método a ser testado) e saídas esperadas. As saídas podem ser um valor de retorno, exceções ou estado do objeto sendo testado. A Figura 6 apresenta uma classe simples e um exemplo de como testá-la utilizando JUnit. A classe a ser testada apresenta um único método, chamado divisao, que recebe dois pontos flutuantes e retorna a divisão dos dois. Caso o divisor seja zero, é lançada uma exceção DivideByZeroException. Para testar essa classe utilizando JUnit 4, primeiramente foi criada uma classe de testes. Esta classe possui dois métodos de teste (iniciados pela anotação @Test). O primeiro deles consiste em instanciar a classe a ser testada, chamar seu método divisao para os valores 30 e 10 e comparar o retorno do método com o resultado esperado. Essa comparação é feita pelo método assertEquals, do JUnit. O segundo teste tenta fazer uma divisão por zero. Para isso, informamos na anotação @Test que esperamos que seja lançada a exceção DivideByZeroException. 38 Figura 6: Exemplo de teste de unidade simples criado com JUnit 4 Outras anotações comuns e muito úteis são @Before, para métodos que devem ser executados antes de cada método de teste e @BeforeClass, para métodos executados uma única vez antes da execução do conjunto de testes. De forma análoga, existem também as anotações @After e @AfterClass. Testes criados a partir do JUnit também facilitam o debug, pois o framework, além de indicar o sucesso/falha dos testes visualmente com uma barra verde (quando o teste passada) ou vermelha (quando o teste falha), também indica, no código, o que desencadeou a falha. Figura 7: Feedback visual do resultado dos testes da Figura 6, na IDE Eclipse4 39 3 Abordagem proposta O objetivo deste capítulo é introduzir a abordagem de testes proposta por este tra- balho, que sugere o uso de dados de contexto independentes de aplicações como entrada para testes. Além disso, é apresentado um formato para armazenar a variação de dados de contexto ao longo do tempo, batizado de context file. Independente de sistemas, con- text files são utilizados como entrada para testes sensíveis ao contexto desenvolvidos pelo framework ConBaT, apresentado no capítulo 4. 3.1 Variação do contexto como entrada para testes Conforme apresentado anteriormente, dados de contexto podem ser compreendidos como toda e qualquer informação relacionada à localização, identidade, atividades ou tempo (ABOWD et al., 1999). Sistemas sensíveis ao contexto são capazes de reconhecer informações de contexto relevantes e tomar decisões de acordo com elas, podendo au- xiliar de forma passiva, silenciosa e eficaz o usuário em suas atividades rotineiras. Um microondas inteligente pode, por exemplo, ser sensível à localização do usuário - que é uma informação do contexto -, obtida através de GPS, e automaticamente esquentar suajanta, de modo que assim que o usuário entre em casa, ela esteja quente e pronta para ser comida. Um celular sensível ao contexto pode perceber quando está dentro de uma sala de reuniões e automaticamente entrar no modo silencioso. Casos de testes em sistemas tradicionais podem ser definidos através de um conjunto de entradas, ao menos um script de teste e um conjunto de saídas esperadas, para cada entrada especificada. Essas entradas podem ser, por exemplo, cliques em botões, inserção de texto em campos de texto, etc. O que vemos nessa situação, entretanto, é um forte acoplamento entre os três elementos envolvidos. Caso o sistema sofra alguma alteração que afete o script de testes em questão, os dados de entrada podem ter que ser revisados, assim como as saídas esperadas. Isso pode gerar um alto custo de manutenção e tornar inviável a automação de testes em sistemas voláteis, isto é, sistemas que têm uma maior 40 tendência a sofrer alterações durante seu desenvolvimento. Este forte acoplamento, por outro lado, não é observado quando utilizamos dados de contexto como entrada para o sistema, pois devido à sua natureza, dados de contexto podem ser independentes de aplicações - o fato de alguém estar chegando em casa ou entrar em uma sala de reuniões é algo que pode acontecer com ou sem a existência de um sistema capaz de monitorar essas ações. Este nível de independência nos permite repensar formas de testar sistemas dependentes do contexto e é nesta ideia que a abordagem de testes apoiada por este trabalho se baseia. 3.2 Exemplo motivador Imaginemos novamente um sistema que aciona automaticamente as luzes de um am- biente ao detectar movimento. Este sistema utiliza um sensor de movimento PIR, que quando consultado, retorna 0 se não houver movimento detectado e 1 se algum movi- mento for detectado. Para este sistema, então, é simples simular o ambiente de execução durante testes automatizados: basta definir uma sequência de 0 e 1 e criar um objeto mock para simular os sensores com esses números sempre que o sistema tentar consultá-los. Imaginemos agora um sistema um pouco mais complexo: vestíveis inteligentes na forma de sapatilha de ballet e presilha de cabelo, que juntos têm como objetivo monitorar e apontar problemas de técnica, durante a prática do ballet clássico. A sapatilha monitora os movimentos da perna, enquanto que a presilha monitora o ângulo da cabeça e, caso haja algo errado durante a prática, fornece um feedback vibratório. O sistema é capaz de monitorar os movimentos da bailarina através de acelerômetros e giroscópios contidos nos vestíveis, ou seja, as entradas de dados no sistema vêm das leituras desses sensores. Surge então a pergunta: Como testar esse tipo de sistema? Primeiramente, podemos notar que não dá pra definir “de cabeça” os valores obtidos pelos sensores durante uma execução real do sistema, visto que as leituras de acelerôme- tros e giroscópios são mais complexas que 0 e 1, além de alimentarem o sistema a uma rápida velocidade, tornando este trabalho humanamente impossível. Uma solução seria então coletar as informações capturadas pelos sensores durante uma execução real do sistema e armazenar essas informações em algum lugar, de modo que durante os testes possamos utilizar um objeto mock capaz de simular os sensores com essas informações. Essa abordagem combina objetos mock com a ideia de capture replay : há uma fase de coleta de dados (capture), que é feita uma vez e que irá gerar um conjunto de entradas 41 para o sistema, e a fase de testes (replay), que utilizará os dados coletados previamente como entrada para o sistema, possibilitando a automação. Figura 8: Uso de capture replay para testar um sistema sensível ao contexto Essa solução deve funcionar, porém não podemos garantir que irá continuar funcio- nando caso haja alguma alteração no sistema. Por exemplo, na Figura 9 temos um gráfico que representa os dados de contexto coletados e simulados pelo uso da técnica de capture replay, ao longo do tempo. Os círculos preenchidos representam as informações captura- das durante a fase de capture e as circunferências representam o momento em que elas são fornecidas ao sistema pelo objeto mock utilizado nos testes, isto é, durante o capture. Como é de se esperar, ambos devem coincidir, visto que o sistema que capturou essas informações é o mesmo sistema que está sob testes. Entretanto, caso haja uma alteração no sistema e este passe a consultar os sensores a uma frequência diferente, teremos o problema retratado pela Figura 10 - o sistema, durante testes, está solicitando informações de contexto em momentos diferentes dos quais as informações mockadas foram coletadas. Os círculos preenchidos representam os dados coletados durante a etapa de capture, as circunferências representam o dados simulados durante o capture e linha com seus picos e vales representam a variação real dos dados de contexto sob o ponto de vista do sensor utilizado, ao longo do tempo. Como podemos observar, os dados simulados para a nova versão do sistema não mais representam o contexto real de execução. Voltamos então ao problema de automação de testes em sistemas voláteis, mencionado anteriormente - um caso de teste afetado por alterações no sistema provavelmente exigirá novas entradas. Como no caso de sistemas sensíveis ao contexto a própria variação do 42 Figura 9: Dados coletados durante a fase de captura em comparação aos momentos em que esses dados são fornecidos pelo objeto mock durantes os testes, ao longo do tempo contexto serve de entrada, esse problema implicaria em uma nova coleta, que traria consigo altos custos de manutenção - por exemplo, contratar novamente uma bailarina, alocar espaço, equipe para a coleta de dados, etc -, tornando a automação inviável. Isso se deu porque utilizamos o próprio sistema a ser testado para coletar as infor- mações do contexto. Ou seja, as informações de contexto simuladas durante os testes do sistema estão fortemente atreladas a uma execução específica de uma versão específica desse sistema, mas não precisam ser. O fato de as entradas do sistema serem variações do contexto nos dá uma vantagem para simulá-las em comparação às entradas de sistemas tradicionais - informações de contexto (uma pessoa chegando em casa, pessoas entrando numa sala de reuniões, bailarinas executando movimentos de ballet, etc) podem ser inde- pendentes de sistemas. Imaginemos então a coleta de dados do contexto sendo feita de forma independente do sistema que será testado. Serão usados os mesmos sensores, mas dessa vez controlados por um outro sistema, que chamaremos de “sistema de coleta” e cuja única função é capturar informações sobre a variação de contexto a uma alta frequência e armazená- las em algum lugar. Se compararmos os dados obtidos pelo sistema de coleta com os obtidos pela execução do sistema real (Figura 11), percebemos que o resultado gerado pelo sistema de coleta, além de conter toda a informação que seria obtida pela execução do sistema real, também apresenta informações sobre o contexto nos momentos em que ele não seria consultado pelo sistema real. Isto é, temos agora ricas informações de variações de contexto, independente de sistema. 43 Figura 10: Variação real dos dados ao longo do tempo, comparados aos dados coletados durante a fase de captura e aos dados fornecidos pelo objeto mock durante testes, após alteração na taxa de leitura dos sensores pelo sistema Figura 11: À esquerda, dados coletados pelo próprio sistema a ser testado. À direita, dados coletados pelo sistema de coleta, em relação ao tempo Como o sistema de coleta nos fornece mais informação do que de fato precisamos, não podemos adotar a estratégia de sempre fornecer o próximo dado disponível durante a simulação dos sensores - é necessário saber quais dados ignorar e quais utilizar. Esta simu- lação sensível ao tempo pode ser possível se, durante a coleta, mantivermos a frequência de capturade dados constante. Assim, de acordo com o tempo passado desde o início da simulação, podemos descobrir qual o dado “correto” a ser retornado ao sistema, sempre que o mesmo tentar ler um sensor. Esta característica faz com que os testes se tornem mais robustos - mesmo para sistemas voláteis, casos de teste afetados por alterações no sistema provavelmente não irão implicar em novas coletas de dados, reduzindo custos de manutenção e possibilitando a automação dos testes. 44 3.3 Visão geral da abordagem proposta Segundo (FEWSTER; GRAHAM, 1999), dados de teste devem estar no formato mais flexível, o mais independente possível de alterações futuras no software sob teste. A abor- dagem proposta por este trabalho condiz com essa afirmação, ao envolver a utilização de informações de contexto, previamente coletadas e independentes de aplicações, como en- trada para os testes. Este trabalho aponta diretrizes para uma boa coleta e documentação de variações de contexto, assim como apresenta o framework ConBaT, no capítulo 4, que apoia essa abordagem desde a atividade de coleta e documentação de variações de contexto à criação dos testes baseados em contexto. 3.3.1 Context files Para que informações sobre variações de contexto sejam reutilizadas, precisamos do- cumentar essa informação de alguma forma. Para isso, foram criados os context files. Um context file nada mais é do que um objeto JSON, contendo informações sobre variações de contexto obtidas através de variados sensores durante um determinado período de tempo. Para facilitar o compartilhamento e compreensão de dados de contexto coletados por outras pessoas, é interessante que haja alguma padronização. As diretrizes para criação de context files bem especificados mencionadas nesta seção são importantes não só para que esses arquivos sejam facilmente compreendidos, como também para que estejam prontos para serem processados pelo framework desenvolvido e apresentado neste trabalho. Antes de continuar falando sobre a estrutura de context files, é importante estabele- cer alguns conceitos. Como mencionado anteriormente, pode-se entender como contexto qualquer informação que possa ser obtida de alguma forma (em sistemas sensíveis a con- texto, através de sensores) e que descrevam localização, identidade, atividades ou tempo (ABOWD et al., 1999). Uma leitura é simplesmente a obtenção de um dado de contexto a partir de um sensor. Uma captura do contexto é o conjunto de leituras de diferentes sensores, representando o contexto sob diferentes perspectivas em um determinado mo- mento. Coletar variações do contexto, por sua vez, significa continuamente capturar e documentar variações dos dados de contexto, ao longo de um determinado período de tempo, com ou sem um intervalo intencional entre estas capturas. O ato de coletar, então, envolve uma série de capturas do contexto, igualmente espaçadas no tempo. A coleta de variações de contexto também será referida neste trabalho simplesmente como “coleta de 45 dados”. É importante que, independente do método utilizado para capturar dados e gerar um context file, o intervalo de tempo entre as capturas de contexto seja constante, pois é o que nos garante uma simulação confiável da variação do contexto ao longo do tempo. O framework proposto por esse trabalho oferece suporte à coleta de dados de contexto, gerando automaticamente context files bem documentados, como o da Figura 12. Um context file deve conter três tipos de informação: (i) detalhes sobre a coleta em si; (ii) informações sobre o significado dos dados coletados; e (iii) os dados crus obtidos durante a coleta. As informações do grupo (i) são descritas pelas chaves name, des- cription, capture_interval e duration - as duas primeiras são Strings e as duas últimas, longs - representando respectivamente o nome do context file, uma breve descrição, intervalo entre capturas de dados e duração total, em milissegundos. As informa- ções do grupo (ii) se encontram em um array de Strings, cuja chave se chama data_info. Cada elemento deste array descreve um tipo de dado obtido pela coleta, como o sensor utilizado ou qualquer outra informação relevante. O grupo (iii) é representado pela matriz de Strings data, cujas linhas representam capturas realizadas durante a coleta - isto é, o conjunto de dados obtidos por diferentes sensores em um determinado momento - e as co- lunas representam os diferentes sensores utilizados. Estas leituras devem estar ordenadas da mesma maneira em que são descritas em data_info. Ao realizar suas próprias coletas de dados, é recomendado que se use o máximo possível de sensores, de modo que o contexto possa ser descrito pelo maior número possível de perspectivas. Além disso, é importante realizar essa coleta com o menor intervalo de tempo possível entre cada captura. Dessa forma, garantimos context files mais ricos em informação, que podem beneficiar um número maior de situações. 3.3.2 Benefícios Dentre os benefícios proporcionados pelo uso de context files para armazenar a varia- ção de dados de contexto ao longo do tempo e para servir de entrada de testes baseados em contexto, podemos citar: Uma coleta de dados de contexto bem feita só precisa ser realizada uma vez e pode carregar informações com grande potencial de reutilização, ser- vindo de entrada para diferentes casos de teste, até mesmo de diferentes funcionalidades do sistema; • Ao trabalhar com context files confiáveis, os testadores não precisam se preocupar 46 Figura 12: Exemplo de um context file com especificação de dados de entrada e podem focar nos scripts de teste e compor- tamento esperado do sistema, aumentando a produtividade e qualidade do processo de especificação de casos de teste; • O processo de definição, especificação e até mesmo coleta de dados de contexto pode ser feita desde o início do desenvolvimento do sistema, por serem independentes do sistema - o que também não impede que novos context files sejam criados e utilizados sem complicações em fases mais avançadas do desenvolvimento do sistema; • Devido à informação contida em context files permitir a simulação de sensores du- rante testes, é possível testar sistemas desde o início de seu desenvolvimento, mesmo que ainda não haja nenhum sensor físico conectado ao sistema sob testes; • Context files que possuem informação de diversos sensores distintos são relevantes tanto para sistemas que consigam explorar todo seu potencial, quanto por siste- mas que só precisem da informação de um ou dois sensores - as informações não necessárias são simplesmente ignoradas; • De modo similar ao ponto anterior, context files coletados a uma alta frequência, 47 isto é, baixo intervalo de tempo entre cada captura, irão servir tanto para sistemas simples que fazem leituras esporádicas quanto para sistemas que fazem leituras mais frequentes - as informações de contexto “entre leituras” são simplesmente ignoradas; • Por serem independentes, contextos coletados e especificados por qualquer pessoa podem ser compartilhados entre desenvolvedores com interesses e projetos distintos; • Mesmo para softwares voláteis, que são um grande problema para a automação de testes devido ao custo de manutenção a cada alteração, a natureza independente de context files pode reduzir consideravelmente tais custos ao reduzir - ou até mesmo eliminar - a necessidade de realização de novas coletas após alterações no sistema. 3.3.3 Outros cenários de uso Como context files carregam ricas informações sobre a variação de dados de contexto ao longo de um determinado período de tempo, sob diferentes perspectivas (diferentes sensores) e de forma independente de qualquer sistema, é de se esperar que tais informações sejam de grande utilidade em diferentes áreas do conhecimento. A área abordada por este trabalho é a de testes de software, que pode fazer uso de contex files para simular sensores e permitir que o sistema seja executado e testado como se estivesse
Compartilhar