Buscar

FrameworkConBaTsuporte-Silva-2021

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

Continue navegando