Saúde Do PC
Saúde Do PC
Saúde Do PC
INSTITUTO DE INFORMÁTICA
PROGRAMA DE PÓS-GRADUAÇÃO EM COMPUTAÇÃO
Agradeço aos meus orientadores Érika e Luba pela oportunidade e aprendizado. Tam-
bém agradeço aos que fazem e se preocupam com a qualidade do ensino e pesquisa dentro
do Instituto de Informática da UFRGS, em especial ao Professor Flávio Wagner. Por fim,
um agradecimento especial aos meus colegas de laborátório, LSE e de sala de aula, pois
a interação com eles proporcionou um aprendizado ainda mais rico.
Obrigado!
SUMÁRIO
LISTA DE FIGURAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
LISTA DE TABELAS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
RESUMO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
ABSTRACT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1 INTRODUÇÃO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2 SELEÇÃO DE TERMINOLOGIAS . . . . . . . . . . . . . . . . . . . . . 15
2.1 Defeito, Falha, Erro e mau funcionamento . . . . . . . . . . . . . . . . . 15
2.1.1 Engenharia de software . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.1.2 Tolerância a Falhas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.1.3 Sistemas Eletrônicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.2 Verificação, Validação e Teste . . . . . . . . . . . . . . . . . . . . . . . . 17
2.2.1 Engenharia de Software e Tolerância a Falhas . . . . . . . . . . . . . . . 17
2.2.2 Sistemas Digitais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.3 Terminologia selecionada para Teste de Sistemas Embarcados . . . . . . 18
2.3.1 Defeito, Falha, Erro e mau funcionamento . . . . . . . . . . . . . . . . . 18
2.3.2 Verificação, Validação e Teste . . . . . . . . . . . . . . . . . . . . . . . . 19
3 TESTE DE SOFTWARE . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.1 Princípios do Teste de Software . . . . . . . . . . . . . . . . . . . . . . . 21
3.2 Testabilidade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.3 Casos de Teste e Cobertura de Teste . . . . . . . . . . . . . . . . . . . . 23
3.4 Critérios do Teste de Software . . . . . . . . . . . . . . . . . . . . . . . . 24
3.5 Técnicas de Teste de Software . . . . . . . . . . . . . . . . . . . . . . . . 25
3.5.1 Teste Funcional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.5.2 Teste Estrutural . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Figura 2.1: Defeito, Falha, Erro e mau funcionamento em teste de sistemas em-
barcados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Figura 2.2: Verificação, validação e teste em teste de sistemas embarcados . . . . 19
Sistemas embarcados estão mais complexos e são cada vez mais utilizados em contex-
tos que exigem muitos recursos computacionais. Isso significa que o hardware embarcado
pode ser composto por vários processadores, memórias, partes reconfiguráveis e ASIPs
integrados em um único silício. Adicionalmente, o software embarcados pode conter mui-
tas rotinas de programação executadas sob restrição de processamento e memória. Esse
cenário estabelece uma forte dependência entre o hardware e o software embarcado. Por-
tanto, o teste de um sistema embarcado compreende o teste do hardware e do software.
Neste contexto, a reutilização de procedimentos e estruturas de teste é um caminho para
se reduzir o tempo de desenvolvimento e execução dos testes. Neste trabalho é apresen-
tado um método de teste integrado de hardware e software. Nesse método, casos de teste
desenvolvidos para testar o software embarcado também são usados para testar o seu pro-
cessador. Comparou-se os custos e cobertura de falhas do método proposto com técnicas
de auto-teste funcional. Os resultados experimentais demonstraram que foi possível re-
duzir os custos de aplicação e geração do teste do sistema usando um método de teste
integrado de software e hardware.
ABSTRACT
Embedded Systems are more complexity. Nowadays, they are used in context that
requires computational resources. This means an embedded hardware may be compound
of several processors, memories, reconfigurable parts, and ASICs integrated in a single
die. Additionally, an embedded software has a lot of programming procedures, which is
under processing and memory constraints. This scenario provides a stronger connection
between hardware and software. Therefore, the test of an embedded system is the test of
both, hardware and software. In this context, reuse of testing structures and procedures
is one way to reduce the test development time and execution. This work presents an
integrated test of software and software method. In this method, test cases developed to
test the embedded software are also used to test its processor. We compared the costs and
fault coverage of our proposed method with techniques of functional self-test. The exper-
imental results show that it is possible to reduce the implementation and test generation
costs using an integrated test of software and hardware.
1 INTRODUÇÃO
necessita de uma visão apropriada para testar com sucesso uma aplicação do software
(MYERS, 2004). Isto é, os casos teste são determinados dependendo da análise realizada
pelo testador, implicando na subjetividade do caso de teste como outro limitador do teste
do software.
Ao se tratar de software embarcado outros aspectos são agregados ao funcionamento
do mesmo. O software embarcado é armazenado em qualquer tipo de memória perma-
nente. Freqüentemente, o código é armazenado em uma ROM, mas também pode ser
armazenado em cartões, ou em disco rígido, ou em CD-ROM, e ainda seu download pode
ocorrer através de uma rede ou de um satélite. O software embarcado é compilado para
um processador (ou plataforma) alvo em particular, ou seja, uma unidade de processa-
mento que requer geralmente uma determinada quantidade de RAM para operar, e tam-
bém, assegura todas as entradas e saídas de sinais com uma camada dedicada de entrada
e saída (BROEKMAN; NOTENBOOM, 2003). Além disso, um sistema embarcado pode
interagir com outros sistemas (embarcados ou não) através de relações específicas, e ge-
ralmente obtém seus recursos de energia (potência) de uma fonte de alimentação própria
e dedicada, como baterias.
De acordo com as características do software embarcado, é factível que o teste de
software embarcado pode ser dividido em duas etapas, uma em ambiente de simulação
e outra em ambiente de execução. A primeira consiste em cobrir falhas inerentes as
funcionalidades especificadas no projeto do software e verificação de como o código do
software está estruturado. A segunda etapa valida o software, executando-o na plataforma
alvo, cobrindo falhas originadas das restrições específicas do ambiente embarcado.
Como o teste de um sistema embarcado compreende o teste do hardware e do soft-
ware, na referida segunda etapa do teste do software pode-se pensar em verificar o hard-
ware, uma vez que em cada, o esforço para gerar e aplicar os teste podem ser enormes.
Assim, a reutilização de procedimentos e estruturas de teste, em todos os níveis, pode
ser uma abordagem interessante para reduzir a complexidade dos testes. Para software
embarcado, metodologias de teste são baseadas em conceitos de engenharia de software.
Por exemplo, a cobertura de teste baseado no código-fonte é um tradicional critério para
medir a qualidade do teste do software (HORGAN; LONDON; LYU, 1994) e válido para
o teste de software embarcado. Quando se trata de hardware, o processador embarcado
é provavelmente o mais complexo componente a ser testado na plataforma. Atualmente,
técnicas auto-teste baseado em software (SBST) para microprocessadores são utilizados
como uma alternativa de baixo custo em relação às abordagens baseadas em hardware,
tais como teste de varredura (scan) e auto-teste (BIST - Built-in Self-test).
Em um processador projetado para executar instruções de um determinado software,
isto é, um sistema embarcado composto de um programa que será executado em um hard-
ware dedicado, é factível um estudo que vise não apenas o uso de técnicas da engenharia
de software para aumentar a testabilidade do hardware, quando aplicado em uma HDL
(Linguagem de de Descrição de Hardware), mas sim explorar melhor essas técnicas de
maneira que aumente a testabilidade do software embarcado com o intuito de também
detectar falhas no hardware (por exemplo, stuck-at), além dos erros e falhas de software.
Baseado nas idéias acima, neste trabalho é apresentado um método de teste que tem
como base a abordagem de teste integrado de software e hardware para sistemas embar-
cados. Um processo que visa o teste para os sistemas em que o hardware é projetado
para executar instruções de um determinado software, isto é, uma versão ASIP (Applica-
tion Specific Instruction set Processor) de um processador, onde sua unidade de controle
possui apenas as instruções usadas por aquele programa em específico.
14
2 SELEÇÃO DE TERMINOLOGIAS
Ao longo do presente trabalho, serão utilizados termos, tais como: defeito, falha,
erro, mau funcionamento, verificação, validação e teste. Esses, principalmente os quatro
primeiros, possuem diferentes definições nas áreas de engenharia de software, tolerância
a falhas (em hardware e em software) e teste de sistemas digitais. A terminologia de cada
área é apresentada nas seções a seguir. Por fim, será selecionada uma combinação entre
essas terminologias para serem empregadas no contexto de teste integrado de software e
hardware.
Nota-se que a tradução dos termos fault e failure, na área de tolerância a falhas, é
oposta à tradução apresentada no contexto da engenharia de software.
• Teste: O teste deve avaliar (verificar) se o dispositivo físico está de acordo com
as especificações, se o circuito tem um comportamento funcional correto, denomi-
nado também de teste funcional, ou se a implementação física do circuito espelha
seu esquemático, também denominado de teste estrutural. Quando o projeto está
implementado em silício pode ser verificado, então, sendo denominado de teste,
correspondendo à fase onde se deve assegurar que somente circuitos livres de de-
feitos sejam comercializados, detectando falhas de fabricação do circuito impresso.
Figura 2.1: Defeito, Falha, Erro e mau funcionamento em teste de sistemas embarcados
19
• Defeito (Defect): Refere-se aos problemas físicos do sistema, isto é, defeito, falha,
erro e mau funcionamento no hardware, conforme visto na seção 2.1.3, que pos-
sam interferir no funcionamento do sistema embarcado, podendo causar um mau
funcionamento do mesmo.
A taxonomia escolhida para compor a definição particular neste trabalho de cada veri-
ficação, validação e teste é a mesma apresentada para as áreas de engenharia de software
e tolerância a falhas, descrita na Seção 2.2.1. A Figura 2.2 demonstra que a atividade
de teste é composta pelo processo de verificação, primeiramente, e posteriormente pela
validação:
3 TESTE DE SOFTWARE
Uma vez especificado ou construído o código fonte, o software deve ser testado. Para
isso, uma série de casos de teste que têm uma grande probabilidade de encontrar falhas e
erros devem ser projetados. Isso é realizado através de técnicas de teste de software que
fornecem diretrizes sistemáticas para projetar os testes (PRESSMAN, 2006).
O principal objetivo das atividades de teste é aumentar a confiabilidade e garantir a
qualidade dos produtos de software produzidos, tendo como principal aspecto do teste
de software encontrar falhas e erros, também aumentando a aceitabilidade do mesmo.
Erroneamente, pensa-se em teste como a forma de provar que o software está correto. Ao
pensar dessa forma o testador tende a produzir casos de teste pobres, com poucas chances
de encontrar erros. Caso contrário, tem-se um bom potencial de produzir casos de teste
para descobrir falhas e erros não detectados (MYERS, 2004).
No âmbito do software de propósito geral, (KRUG, 2007) comenta que entre os de-
senvolvedores de aplicativos é comum dizer que o mau funcionamento do software só
aparece quando o usuário (cliente) vai utilizar o sistema, isto é, quando o mesmo já está
em uso. Isso acontece porque o desenvolvedor ao realizar os testes o faz de forma vici-
osa, fazendo-os em cima das consistências existentes em seu programa, enquanto que o
usuário, sob as mais variadas condições, irá utilizar o sistema para diversas situações e
combinações, que em muitos casos não foram simuladas na fase de desenvolvimento do
software. Portanto, deve-se destacar que o software deve estar preparado para qualquer
situação, que são formuladas em forma de casos de teste.
• Um programador deve evitar testar seu próprio programa: depois que um progra-
mador projetou e codificou, de forma “construtiva”, um programa, é extremamente
difícil mudar a perspectiva de maneira que tenha visão “destrutiva” do seu traba-
lho. Além disso, o software pode conter erros devido às falhas do programador na
22
• Uma equipe de programadores não deve testar seus próprios programas: os argu-
mentos anteriores se aplicam a este caso, mas somado ao fato de uma equipe ser
avaliada em produzir um software em um dado tempo com um certo custo, difi-
cultando o discernimento em quantificar a confiabilidade do produto. Dessa forma,
implicando, ao final, ser mais econômico que o teste seja executado por um grupo
com o objetivo de somente testar.
• Os casos do teste devem ser escritos para as condições da entrada que são inválidas
e inesperadas, bem como para aquelas que são válidas e esperadas: A tendência
natural é produzir casos de teste com entradas válidas e esperadas. Porém, mui-
tos erros são descobertos quando o programa é usado em alguma maneira nova ou
inesperada. Conseqüentemente, os casos do teste que representam condições ines-
peradas e inválidas da entrada parecem ter um rendimento mais elevado na detecção
de erros do que testar argumentos para condições válidas da entrada.
• Examinar um programa para verificar se não faz o que se propôs a fazer é somente
metade do caminho; a outra metade está em ver se o programa faz o que não se
propõe para fazer: justificativa semelhante ao princípio anterior. Os programas
devem ser examinados para efeitos não desejados.
• Evitar casos de teste throwaway (de exame rápido) a menos que o programa seja
verdadeiramente um de throwaway: Uma prática comum é sentar-se em um termi-
nal e inventar os casos de teste on the fly. O problema principal é que os casos do
teste representam um investimento valioso que, nesse ambiente, desaparece depois
que o teste foi terminado.
• Não planejar testes sob a suposição implícita que nenhum erro será encontrado:
não supor que o teste é um processo para mostrar que o programa funciona cor-
retamente, uma vez que, a definição de teste determina em ser é um processo que
executa um programa com o objetivo de encontrar falhas e erros.
parecem ser muito mais propensa aos erros do que as demais, os esforços em testes
adicionais devem ser focalizados nessas seções.
3.2 Testabilidade
A testabilidade é definida como a capacidade de testar certos atributos internos ao
sistema ou facilidade de realizar certos testes. É uma das medidas de dependabilidade
(dependability), que é o objetivo de tolerância a falhas. Assim, quanto maior a testabili-
dade, melhor a mantenabilidade, por conseqüência menor o tempo de indisponibilidade
do sistema devido à reparos. A mantenabilidade é a facilidade de realizar a manutenção do
sistema, isto é, a probabilidade que um sistema com mau funcionamento seja restaurado
a um estado operacional dentro de um período determinado (WEBER; WEBER; PORTO,
1990).
O software ou uma unidade do software é testável por um domínio se esse é controlá-
vel e observável, podendo ser modificado para ser testável por um domínio pela adição de
todas as variáveis usadas no software em parâmetros de entrada e reduzindo as saídas de-
claradas para uso de domínios reais. Entende-se por domínio os valores possíveis que uma
variável pode assumir de acordo com sua declaração (tipo de dado e tamanho). Em outras
palavras, um produto é testável se oferece suporte a geração de testes, implementação e
verificação de seus resultados de forma precisa.
No contexto de hardware, a controlabilidade refere-se à facilidade de controlar certo
valor lógico em um ponto determinado do circuito, através da modificação dos valores das
entradas do mesmo. Já a observabilidade avalia a facilidade de observar o valor lógico
de um dado ponto do circuito nas saídas primárias desse (ABRAMOVICI; FRIEDMAN;
BREUER, 1990).
o conjunto de casos de teste pode ser aprimorado, acrescentando-se novos casos de teste
para exercitar os elementos ainda não cobertos.
Figura 3.1: Representação da relação de dependência dos casos de testes com a especifi-
cação.
O teste estatístico de software (statistical software testing) também pode ser visto
como teste funcional uma vez que o mesmo também leva em conta a especificação do
software para gerar o conjunto de teste. Exemplos de tais critérios podem ser encontra-
dos em (THéVENOD-FOSSE; WAESELYNCK, 1993; WHITTAKER; M.THOMASON,
1994; WHITTAKER, 1997). A idéia desses critérios é a de exercitar um programa com
valores aleatórios selecionados do domínio de entrada utilizando-se uma função de dis-
tribuição. Assim, a eficácia desses critérios está condicionada à capacidade de se derivar
uma função de distribuição que maximize a probabilidade de uma entrada que revele fa-
lhas. Basicamente, como definido por (THéVENOD-FOSSE; WAESELYNCK, 1993), os
conjuntos de testes estatísticos são definidos por dois parametros: (i) o perfil de teste, ou a
distribuição de entrada a partir da qual os dados de teste são selecionados aleatoriamente;
e (ii) o número de dados de teste a serem gerados.
Em (OFFUTT; IRVINE, 1995) foi conduzido um estudo piloto para avaliar a aplicação
dos critérios de teste funcional no contexto de programas orientado a objetos e observam
que não existem evidências de que as técnicas e critérios de teste tradicionais, destina-
das ao teste de programas procedimentais, tenham ineficácia para o teste de programas
orientado a objetos. Os resultados obtidos por (OFFUTT; IRVINE, 1995) indicam que
a combinação do método de partição de equivalência com uma ferramenta para detectar
erros de alocação e desalocação de memória pode ser uma estratégia de teste eficaz para
o teste de programas C++.
Figura 3.3: Representação da relação de dependência dos casos de testes com o código
da aplicação.
trole da execução do programa, como comandos ou desvios, para determinar quais es-
truturas são necessárias. Os critérios mais conhecidos dessa classe são: (i)Todos-os-Nós
- exige que a execução do programa passe ao menos uma vez em cada vértice do grafo
de fluxo, ou seja, que cada comando do programa seja executado pelo menos uma vez;
(ii)Todos-os-Arcos - requer que cada aresta do grafo, ou seja, cada desvio de fluxo de
controle do programa, eja exercitada pelo menos uma vez; e (iii)Todos-os-Caminhos -
requer que todos os caminhos possíveis do programa sejam executados (MALDONADO
et al., 1998).
b) Critérios Baseados em Fluxo de Dados: utilizam informações do fluxo de dados do
programa para determinar os requisitos de teste. Esses critérios exploram as interações
que envolvem definições de variáveis e referências a tais definições para estabelecerem
os requisitos de teste. Exemplos são: (i)Todos-os-Usos - requer que todas as associações
entre uma definição de variável e seus sub-seqüentes usos sejam exercitadas pelos casos
de teste, através de pelo menos um caminho livre de definição, ou seja, um caminho
onde a variável não é redefinida; (ii)Todos-os-Potenciais-Usos - procura explorar todos os
possíveis efeitos a partir de uma mudança de estado do programa em teste, decorrente de
definição de variáveis em um determinado nó (MALDONADO et al., 2004).
A Figura 3.4 apresenta três tipos de visões para análise da cobertura de teste pela Ja-
BUTi: (i) visão de código, apresentando os niveis profundidade das linhas de código, isto
é, se o teste atingir determinada linha de código fez com que o teste também exercitasse as
linhas de nível de profundidade inferior; (ii) visão de grafos, baseados nos conceitos dos
grafos IG e DUG; (iii) cobertura por caso de teste, apresentando o percentual de cobertura
de teste, isto, percentual do código que é exercitado pelo caso de teste. Considerando o
suporte à análise de cobertura de programas Java, foram analisados quatro critérios de
teste intra-métodos implementados pelo JaBUTi, sendo dois de fluxo de controle (Todos-
Nós,Todas-Arcos) e dois critérios de fluxo de dados (Todos-Usos e Todos-Pot-Usos).
Analisando a Tabela 3.1, podem ser observados alguns pontos com relação as ferra-
mentas de testes. Primeiramente, considerando as ferramentas que permitem a avaliação
de cobertura de código por meio de critérios estruturais, observa-se que das ferramentas
analisadas todas apóiam somente o teste de fluxo de controle (cobertura de comandos e
decisões) em programas. Nenhuma delas apóia a aplicação de algum critério de fluxo
de dados, seja para o teste de unidade, integração ou sistema. Além disso, exceto pela
ferramenta GlassJAR e as que apóiam o teste funcional, todas as demais necessitam do
código fonte para a aplicação dos critérios, dificultando a utilização das mesmas no teste
estrutural de componentes de software por parte dos clientes, os quais, em geral, não têm
acesso ao código fonte.
Outro ponto a ser destacado é o fato do framework (arcabouço) JUnit ser uma fer-
ramenta que pode ser utilizada tanto para o teste de programas quanto para o teste de
componentes de software desenvolvidos em Java, porém tal ferramenta suporta apenas a
realização de testes funcionais, não fornecendo informação sobre a cobertura de código
obtida por determinado conjunto de testes. Outra ferramenta que também apóia somente
o teste funcional é a CTB (BUNDELL et al., 2000).
onde:
• TU = Teste de Unidade
• TI = Teste de Integração
• TS = Teste de Sistema
• CF = Critérios Funcionais
• CM = Critérios de Mutação
• EC = Exigências de Código
• AD = Atividade de Depuração
31
• TR = Teste de Regressão
Além disso, considerando as ferramentas que apóiam o teste baseado em erros, observa-
se que todas dão suporte ao teste de integração inter-classe. Embora o teste de integração
seja de grande importância no contexto de programas orientados a objetos, considera-
se que ainda assim, os testes de unidade devam ser realizados visando, principalmente,
eliminar as falhas de lógica e de programação antes das unidades individuais serem inte-
gradas.
Com base nas considerações relacionadas ao teste estrutural foi apresentado um con-
junto de critérios de teste que viabiliza a realização do teste de fluxo de controle e de
dados intra-método em programas Java. Tais critérios derivam os requisitos de testes di-
retamente a partir de bytecodes Java, podendo ser utilizados tanto no teste de programas
quanto de componentes desenvolvidos em Java. Para apoiar a aplicação desses critérios e
suprir parte das deficiências apresentada por outras ferramentas destinadas ao teste estru-
tural de programas, a ferramenta JaBUTi foi selecionada na aplicação prática do processo
proposto neste trabalho, conforme descrito no Capítulo 5.
32
• Alvo do teste: depende da etapa de projeto que é aplicado, o qual tenta identificar
erros de projeto (verificação de projeto), erros e defeitos de fabricação (teste de
aceitação e burn-in), defeitos físicos imediatas (teste de qualidade) e defeitos físicos
que ocorrem durante o uso do sistema (teste de campo ou teste de manutenção);
• Análise dos resultados obtidos: pode-se observar todas as saídas ou apenas algumas
funções (teste compacto);
• Objeto do teste: o objeto de teste pode ser um circuito integrado (teste de compo-
nente), uma placa (teste de placa) ou um sistema com vários níveis de complexidade
(teste de sistema).
2000b).
projeto de um processador é a potência máxima que pode ser dissipada pelo circuito. Tal
limitação é usualmente dada pelo custo do resfriador e dos mecanismos de remoção de
calor, ou pelo consumo de energia (MORAES, 2006).
As técnicas para o auto-teste de processadores embarcados são aplicadas com sérias
dificuldades e restrições devido às arquiteturas otimizadas desses processadores, as quais
admitem, num melhor caso, alterações periféricas no circuito e impacto marginal no de-
sempenho e no consumo de energia (GIZOPOULOS; PASCHALIS; ZORIAN, 2004). A
técnica de auto-teste baseado em software (SBST - Software-Based Self-Test) é bastante
adequada para aplicação em processadores embarcados (MORAES, 2006). Sendo uma
estratégia não intrusiva de teste on-line, o SBST não implica incremento de hardware,
nem adiciona atraso nos caminhos críticos do circuito. Assim, a aplicação dessa técnica
não tem qualquer impacto na área, na potência dissipada, e na freqüência de operação do
processador. O impacto causado no desempenho total do sistema será mínimo desde que
o tempo de execução do teste seja muito pequeno em relação aos processos da aplicação
em execução.
Auto-teste baseado em software (SBST) é uma metodologia alternativa ao auto-teste
baseado em hardware (HBST -Hardware-Based Self-Test) que realiza o teste do proces-
sador usando suas próprias instruções (CHEN; DEY, 2001). Os tTipos de HBST mais co-
nhecidos são o teste de varredura (scan test) e o BIST (Built-In Self-Test) (BUSHNELL;
AGRAWAL, 2000b). O teste de varredura modifica os registradores (flip-flops) do sistema
para que passem a possuir dois modos de operação: modo normal e de teste. O BIST é
uma técnica que utiliza partes do circuito para testar internamente o restante do circuito.
Enquanto o HBST precisa ser aplicado em um modo de operação não funcional, o SBST
pode ser aplicado no modo de operação normal do processador, sem a necessidade de
quaisquer alterações de projeto nem a adição de estruturas de hardware.
O princípio básico do SBST consiste na geração de um programa de auto-teste efici-
ente que alcance alta cobertura de falhas, em caso de teste estrutural, ou que cubra todas
as funções do sistema, em caso de teste funcional. O conceito dessa metodologia pode
ser observado na figura 4.1 (XENOULIS et al., 2003). O programa de auto-teste é arma-
zenadas na memória de instruções, e os dados necessários para sua execução, bem como
as respostas obtidas e esperadas, são armazenados na memória de dados (considera-se
aqui uma arquitetura Harvard, na qual instruções e dados são armazenados em memórias
separadas).
37
O método proposto neste trabalho tem como base uma abordagem de teste integrado
de software e hardware para processadores embarcados. Um método que visa o teste para
os sistemas em que o hardware é projetado para executar instruções de um determinado
software, isto é, uma versão ASIP (Application Specific Instruction set Processor) de um
processador, onde sua unidade de controle possui apenas as instruções usadas por aquele
programa específico. O principal objetivo é atingir um percentual de reuso dos casos
de testes projetados para o teste do software no teste de hardware, assim tendo o teste
integrado de software e hardware (MEIRELLES; COTA; LUBASZEWSKI, 2008). Tal
abordagem é definida e detalhada na próxima Seção 5.2.
Uma vez que o processador (hardware) será gerado a partir do código do software, foi
avaliado um mecanismo de verificação desse hardware através dos testes desenvolvidos
para verificar e validar o software. Para verificar o software são usadas as ferramentas de
testes que permitem aplicar as técnicas e observar os critérios de teste de software. Po-
rém, para validar esse software é necessário executá-lo no ambiente em que será operado.
Neste ponto do fluxo de projeto o hardware ainda não está pronto, além disso, se quer
integrar os testes. Então, a integração deve ser viabilizada por um ambiente de simula-
ção “híbrido” da plataforma alvo, o que permite a validação do software e verificação do
hardware quando os mesmos forem submetidos às condições de falhas.
As rotinas de teste geram ou salvam os padrões de teste para todos os componentes sob
teste, focando as falhas estruturais. As rotinas de auto-teste constituem justamente um
programa de teste que é executado periodicamente. Embora essa abordagem tenha custos
mais elevados do que o SBST funcional, necessita de menos instruções para atingir uma
alta cobertura de falhas.
Em (BECK FILHO et al., 2005) demonstrou que um processador Java (arquitetura
baseada em pilha) requer muito menos instruções aleatórias que um processador com
arquitetura baseada em load-store para ser testado. Isso porque, uma vez que todas as
operações de um processador baseado em pilha usa a mesma estrutura – a pilha – assim,
todas as instruções no programa de teste contribuem para o teste. Dessa forma, o esforço
de teste para essas arquiteturas podem ser reduzidas. No entanto, um programa de teste
ainda deve ser gerado apenas para se obter uma alta cobertura de teste.
Em suma, neste trabalho assumiu-se uma estratégia de SBST funcional como caso
base. De tal modo que é proposto um método para reduzir ainda mais o esforço de geração
dos testes ao usar o próprio software e seus casos de teste para verificar o processador.
seja, teste de software que cobriu as falhas de hardware. Assim a nova visão e equação
para o teste de um sistema embarcado é demonstrada pela Figura 5.2 (MEIRELLES;
COTA; LUBASZEWSKI, 2008).
Figura 5.2: Equação dos custos do teste do sistema embarcado com teste integrado.
Com o reuso do teste de software para o teste do hardware, se obtém um ganho que
compense os custos da aplicação do teste integrado, desde que se conheça quais partes do
hardware não foram cobertas pelo teste integrado para que se aplique uma técnica de teste
de hardware apenas nessas partes.
• em caso negativo, definir novos casos de teste específicos para erros visíveis apenas
no ambiente de execução;
42
• caso positivo, analisar se todos os casos de teste projetados precisam ser embarca-
dos junto ao software para detectar as falhas de hardware.
Figura 5.3: Fluxo das etapas do método de teste integrado de software e hardware.
banco de registradores onde está localizada a pilha podem ser reduzidos em média de
70% em aplicações típicas de sistemas embarcados, pelo fato do processador ser baseado
45
em uma máquina de pilha. Assim, uma das principais características da versão pipeline é
a implementação da pilha de operandos e do repositório de variáveis locais do método em
um banco de registradores, ao invés da memória de dados, como no FemtoJava multiciclo.
Uma outra característica peculiar do FemtoJava pipeline, que foi observada durante a
análise da arquitetura neste trabalho, é a existência de instruções com múltiplos ciclos de
execução dentro do pipeline. Essa característica é normalmente esperada em arquiteturas
do tipo multiciclo e sua adoção dentro de uma arquitetura de pipeline exige uma máquina
de controle mais sofisticada, que permita “travar” o fluxo de execução das instruções
adjacentes por um certo número de ciclos enquanto a instrução atual gera vários sinais
diferentes para todos os estágios a partir de um determinado ciclo. Esse comportamento é
decorrente da existência de instruções complexas, definidas na especificação da máquina
virtual Java (SUN-MICROSYSTEMS, 1999), que necessitam de uma seqüência de sub
operações para serem realizadas.
5.3.2.2 SASHIMI
O SASHIMI é um ambiente destinado à síntese de sistemas microcontrolados especi-
ficados em linguagem Java. O ambiente SASHIMI utiliza as vantagens da tecnologia Java
e fornece ao projetista um método simples, rápido e eficiente para obter soluções baseadas
em hardware e software para microcontroladores. O conjunto de ferramentas disponível
no SASHIMI também foi desenvolvido inteiramente em Java, tornando-o portável para
diversas plataformas (ITO; CARRO; JACOBI, 2001)
O projetista pode modelar, simular e construir uma implementação do sistema direta-
mente em Java, já que o SASHIMI disponibiliza bibliotecas e permite um mapeamento
direto das classes usadas para simulação para o código da implementação final. A partir
do código gerado pelo compilador Java, uma versão ASIP do FemtoJava é gerada, onde
sua unidade de controle possui apenas as instruções usadas por aquele programa em espe-
cífico. O fluxo completo do SASHIMI pode ser observado na Figura 5.8 (ITO; CARRO;
JACOBI, 2001).
As demais versões do Femtojava foram baseadas na versão multiciclo, implemen-
tando o mesmo conjunto de instruções, bem como projetadas de forma que elas sejam fa-
47
• O arquivo que agrega uma função de cálculo de potência para cada componente.
zero (stuck-at-0), posteriormente declarando sempre em zero o segundo bit dos sinais e
mantendo o primeiro com seu valor original. O procedimento é repetido para todos os
bits de todos os sinais até o último bit do último sinal ser atingido e simulado. O mesmo
ocorre para stuck-at-1. Caso tenha dois mil bits nos sinais da arquitetura serão injetadas
quatro mil falhas e quatro mil simulações serão realizadas. Ao final de cada simulação
os valores da memória “ouro”, armazenados na primeira rodada, são comparados com a
memória da simulação com falhas.
A comparação entre as memórias da simulação sem falhas e com das simulações com
falhas também depende do método usado. Por exemplo, o método de teste funcional
usando instruções randômicas (BECK FILHO et al., 2005) percorre toda a memória e ve-
rifica todos os endereços, comparando os valores entre a memória ouro e a memória com
falha. A detecção das falhas no caso do método de teste integrado de software e hardware
não faz comparações entre as memórias, apenas em pontos específicos da memória com
falhas são observados de acordo com o número de casos de testes embutidos no código
do software embarcado. Assim, caso sejam selecionados três casos de testes, apenas três
pontos da memória serão comparados, pois correspondem a variáveis no programa que
indicam se o caso de teste detectou ou não a falha.
Finalizada toda a simulação, o simulador mostra em uma tabela se a falha de cada
bit propagou ou não para a memória, ou para algum sinal em específico, escolhido pelo
usuário. Uma listagem dos bits dos sinais que não foram detectados também é informada,
com isso, sendo possível ao testador de hardware focar a construção dos vetores de teste,
em caso de querer complementar os testes por técnicas de teste de hardware.
Tabela 5.1: Cobertura de falhas de hardware com casos de testes de software no Femto-
Java multiciclo com aplicação de fluxo de dados.
Os resultados apresentados nas Tabelas 5.1 (falhas injetadas = 1.676) e 5.2 (falhas
injetadas = 2.178) demonstram boa cobertura de falhas com o método de teste integrado
aplicado ao FemtoJava. As melhores coberturas estão relacionadas às falhas no PC (falhas
que afetaram também o contador de programa), mas não ao número de ciclos e ao tamanho
das entradas. A principal razão para a boa cobertura de falha é o fato de todos os casos
de teste de software verificarem os resultados em tempo de execução, conforme pode ser
observado na Figura 5.10 (MEIRELLES; COTA; LUBASZEWSKI, 2008). Assim, se
uma falha interfere nas rotinas de teste, ou não o faz executar, a falha é indicada porque
também atingiu o PC (Program Counter).
Tabela 5.2: Cobertura de falhas de hardware com casos de testes de software no Femto-
Java pipeline com aplicação de fluxo de dados
Um dado não detalhado nas tabelas citadas, mas analisando separadamente stuck-at-1,
a melhor cobertura observada foi de 94% para o algoritmo de ordenação (com entradas
variando de 5 negativo à 5 positivo) no FemtoJava pipeline. Essa melhor cobertura é
explicada pelo fato de se ter uma grande quantidade de “Os” (zeros) circulando nos sinais
da arquitetura – circuito aberto, especialmente onde não há fluxo dos dados de entrada.
Para poder comparar os dados das Tabelas 5.1 (falhas injetadas = 1.676) e 5.2 (falhas
injetadas = 2.178), dentro do escopo que considera-se que em um sistema embarcado o
processador é específico para um pequeno grupo de aplicações, é possível considerar a
utilização do aplicativo em si como o teste do programa. Assim, as Tabelas 5.3 e 5.4
mostram os resultados quando um algoritmo de ordenação é utilizado como um programa
de teste para o FemtoJava multiciclo e pipeline. Essas últimas tabelas contêm o mesmo
tipo de informação das primeiras.
52
Os resultados de ambas as tabelas mostram que se obteve uma boa cobertura de falhas
da arquitetura quando um aplicativo (algoritmo de ordenação) é considerado um conjunto
de rotinas de aleatória (full randon) (BECK FILHO et al., 2005). Porém, em todos os
casos de intervalos de dados ordenados, o método de reuso dos casos de teste de software
apresenta melhores resultados que a abordagem de rotinas aleatórias. Uma observação
interessante é o número de instruções no algoritmo de ordenação ser de 57 instruções
(mais detalhes na Tabela 5.6), podendo ser comparado com os dados apresentados em
(BECK FILHO et al., 2005), onde a cobertura de falhas para 50 instruções aleatória no
FemtoJava multiciclo é de 90,11% e para a arquitetura pipeline é de 41,4%. No entanto,
para atingir essa cobertura de falhas é necessário armazenar e verificar todos dos dados da
memória durante o teste, fazendo com que o custo dos testes seja praticamente inviável,
quando se tratando de aplicações maiores.
A Tabela 5.5 apresenta os resultados dos testes em uma aplicação de fluxo de controle
denominada Crane (controle de guindaste) (MOSER; NEBEL, 1999) desenvolvida para
o FemtoJava. Na primeira coluna dessa tabela se tem o números de falhas injetadas na
aplicação, o número de ciclos para executar a aplicação junto com os testes e as coberturas
de falhas obtidas. No FemtoJava os resultados de cobertura de falhas para os testes em
aplicações de fluxo de dados e de fluxo de controle são similares, isso ocorre porque o
número de bits de controle e o de dados são equilibrados. Em sua arquitetura existem
mais sinais de controle, mas com poucos bits, e poucos sinais de fluxo de dados, porém
esses com muitos bits. Porém observa-se em aplicações um pouco mais complexas que
o número de ciclos aumenta consideravelmente quando acrescidas as rotinas de testes.
Especificamente nesse experimento o simulador “híbrido” (CACO-PS) não foi eficiente
em relação ao tempo da execução da aplicação mais as rotinas de teste, consumindo dias
para o término dos estudos de caso.
Na Tabela 5.5 é observada uma comparação entre os custos do uso de uma técnica de
53
Tabela 5.5: Cobertura de falhas dos casos de teste no FemtoJava pipeline em uma aplica-
ção de fluxo de controle.
SBST funcional (full random) e o método de teste integrado (baseado nos casos de teste
de software) proposto neste trabalho. Primeiramente, os custos do SBST funcional são
correspondentes aos estudos de caso, tendo o algoritmo de ordenação sem os casos de
teste como um conjunto de instruções consideradas randômicas, o que não apresenta ne-
nhum custo em relação ao desenvolvimento de rotinas de teste. Já os custos referentes ao
método de teste integrado refletem o acréscimo das rotinas de teste (como observado na
Figura 5.10) no software embarcado para validar o software na plataforma alvo e verificar
o hardware do sistema embarcado. Porém, na Tabela 5.6 outras métricas são abordadas
para comparar outros custos dessas abordagens. Tais métricas são: tamanho do programa,
tamanho da memória, número de opcodes diferentes usados e número de ciclos para exe-
cutar os testes.
Tabela 5.6: Custos das abordagens de SBST funcional e teste integrado para um algoritmo
de ordenação.
é simples porque para o método de teste integrado não é necessário armazenar e com-
prarar a RAM sem falhas com a RAM após a execução com falhas, diferentemente da
abordagem de macros (HENTSCHKE et al., 2006) e totalmente aleatório (full randon)
(BECK FILHO et al., 2005). Assim, há um equilíbrio do tempo de simulação e custos do
método de teste integrado.
No gráfico ilustrado na Figura 5.11 (MEIRELLES; COTA; LUBASZEWSKI, 2008)
é apresentada uma comparação entre os custos na memória de detecção dos métodos de
SBST funcional (full randon) e de teste integrado. Observa-se uma redução do número
de bits comparados,o que demonstra outro ganho além do reuso dos casos de testes de
software por parte do método de teste integrado. A Figura 5.11 ilustra um gráfico com nú-
mero de bits da RAM comparados para verificar a detecção de falhas inseridas nos sinais
da arquitetura do FemtoJava (para um algoritmo de ordenação). Como a técnica SBST
funcional totalmente aleatória compara toda a memória, o custo da detecção é obtido pelo
tamanho da RAM (35X16 bits = 560). A detecção das falhas pelo teste integrado é rea-
lizada na verificação de específicos endereços de memória, observados de acordo com o
número de casos de teste embarcado no código do software. Assim, para o algoritmo de
ordenação (bubble sort) foram selecionados 3 casos de testes, então somente 3 pontos da
memória (3x16 bits = 48) são checados (se uma dessas variáveis for igual a 1 há falha),
porque variáveis são adicionadas ao programa e elas indicam se ocorreu ou não a falha.
Figura 5.12: Detalhes das saídas das simulações com injeções de falhas.
se deve ao fato de que alguns registradores do banco são utilizados para outros propósitos
(MORAES, 2006).
A Tabela 5.7 apresenta os resultados de uma séries de simulações envolvendo a rotina
de teste do banco de registradores para as versões pipeline e multiciclo do FemtoJava,
combinadas ou não com os casos de teste de software para o algoritmo de ordenação, já
citado anteriormente.
De acordo com (MORAES, 2006), nessa rotina são executadas as instruções iadd,
isub, iand, ior e ixor com as quatro possíveis combinações em que todos os bits de cada
operando têm o mesmo valor (0x0000 e 0xFFFF). Em seguida, a instrução ineg é execu-
tada sobre os operandos 0x0000, 0x5555, 0xAAAA e 0xFFFF. Devido à regularidade na
estrutura interna da ULA, a aplicação desses operandos é suficiente para a obtenção de
uma alta cobertura de falhas (MORAES, 2006).
A Tabela 5.8 apresenta os resultados das simulações com a rotina de teste da ULA
para as versões do FemtoJava, da mesma forma como os experimentos com a rotina de
teste do banco de registradores, combinadas ou não com os casos de teste de software
para o algoritmo de ordenação.
Na Tabela 5.8 também são apresentados a versão do FemtoJava a que se referem os
dados, se foi combinado com os casos de teste de software ou não, também o número
de ciclos para ser executado, número de falhas injetadas, a cobertura de teste obtida e o
número de falhas que atingiu o contador de programa. Os resultados são similares aos
obtidos com o banco de registrado, devido às próprias características da biblioteca de
auto-teste, descritas no início desta seção. Observa-se nos dados uma variação pequena
59
trutural de qualquer arquitetura, sendo de propósito geral. Assim, o ambiente não simula
exatamente o ASIP específico correspondente ao software desenvolvido. Mesmo para os
casos das rotinas de hardware a cobertura não é máxima porque o CACO-PS testa todas
entradas de um componente, com isso varia a entrada de dados chamando a função do
comportamento para verificar a alteração na saída. Por exemplo, comparando com uma
simulação em SystemC (GROTKER, 2002) (uma linguagem de modelagem de hardware
de alto nível baseado em C++) se pode define as entradas às quais os componentes serão
sensíveis (como um flip-flop). Além disso, em SystemC pode ser definido que só deve cha-
mar a função quando o clock variar (BARCELOS, 2008). Dessa forma, somando todos
os componentes é possível se obter uma variação no resultado dos testes. Como o desen-
volvimento de um simulador não é o foco deste trabalho, o CACO-PS se apresenta com
uma boa ferramenta para se constituir o ambiente híbrido de validação do método de teste
integrado de software e hardware aplicado ao FemtoJava, apresentando bons resultados
de cobertura de falhas.
61
6 CONSIDERAÇÕES FINAIS
Neste trabalho foi apresentado um método de teste que tem como base a abordagem
de teste integrado de software e hardware para sistemas embarcados. Esse método visa
o teste para os sistemas em que o hardware é projetado para executar instruções de um
determinado software. Esse tipos hardware é uma versão ASIP (Application Specific
Instruction set Processor) de um processador, onde sua unidade de controle possui apenas
as instruções usadas por aquele programa em específico.
Foi realizado um levantamento das terminologias em diferentes áreas (engenharia de
software, tolerância a falhas e sistemas digitais) que norteiam os assuntos tratados nesta
dissertação, selecionando uma terminologia comum para uma melhor compreensão do
mesmo. Como o método de teste proposto parte da engenharia de software, um estudo dos
conceitos, critérios e diferentes técnicas de teste de software, sinalizando como aplicá-los
no teste de software embarcado foi apresentado. Neste contexto, também foram apre-
sentadas algumas ferramentas para automatizar os testes. Posteriormente, levantou-se
problemas em relação ao teste de processadores, descrevendo tipo e técnicas de auto-teste
para microprocessadores, enfatizando o modelo de falhas (stuck-at), utilizado para a in-
jeção de falhas nos estudos de caso deste trabalho. Além disso, as técnicas de auto-teste
de processadores baseado em software foram discutidas e comparadas com o método de
teste integrado proposto. Com a visão geral da área de testes nos dois mundo (software
e hardware) e as questões de testes em microprocessadores, foi possível apresentar um
modelo prático do método de teste integrado. Por fim, foram apresentados uma instância
do que foi colocado teoricamente num modelo conceitual independente de plataforma e
os resultados dos estudos de caso - uma aplicação de fluxo de dados (um algoritmo de
ordenação) e uma aplicação de fluxo de dados (controle de guindaste).
6.2 Conclusão
O principal objetivo do método de teste integrado é atingir um percentual de reuso
dos casos de testes desenvolvidos para o teste do software no teste de hardware, o que
constitui o teste integrado de software e hardware. Uma vez que o processador (hardware)
é gerado a partir do código do software, foi avaliado um mecanismo de verificação desse
hardware através dos testes para verificação e validação do software. Para verificar o
software são usadas as ferramentas de testes (JUnit e JaBUTi) que permitiram aplicar as
técnicas e observar os critérios de teste de software. Entretanto, para validar esse software
é necessário executá-lo. Neste ponto do fluxo de projeto, o hardware ainda não está
pronto, porém uma integração dos testes tornou-se uma abordagem interessante. Então,
a integração deve ser viabilizada por um ambiente de simulação “híbrido” da plataforma
alvo, permitindo a validação do software e verificação do hardware quando os mesmos
forem submetidos às condições de falhas.
Apenas com o reuso dos testes de software para a verificação do hardware foi obtido
uma cobertura de falhas (com o modelo de falhas stuck-at) de até 86% para a versão
63
REFERÊNCIAS
CRAIG, R. D.; JASKIEL, S. P. Systematic Software Testing. [S.l.]: Artech House, 2002.
GALAY, J. A.; CROUZET, Y.; VERNIAULT, M. Physical Versus Logical Fault Models
MOS-LSI Circuits: impact of their testability. IEEE Transactions on Computers, [S.l.],
v.29, n.6, p.527–531, 1980.
GROTKER, T. System design with SystemC. Norwell, MA, USA: Kluwer Academic
Publishers, 2002.
HORGAN, J. R.; LONDON, S.; LYU, L. R. Achieving Software Quality with Testing
Coverage Measures. Computer, [S.l.], v.27, n.9, p.60–69, September 1994.
ITO, S. A.; CARRO, L.; JACOBI, R. Making Java Work for Microtrolles Applications.
IEEE Design & Test of Computer, [S.l.], v.18, n.5, p.100–110, 2001.
66
LALA, P. K. Digital Circuit Testing and Testability. San Diego: Academic Press, 1997.
LAPRIE, J.-C. Dependability of Computer Systems: from concepts to limits. In: IFIP IN-
TERNATIONAL WORKSHOP ON DEPENDABLE COMPUTING AND ITS APPLI-
CATIONS, Johannesburg, South Africa. Proceedings. . . [S.l.: s.n.], 1998.
LUBASZEWSKI, M.; COTA, E.; KRUG, M. R. Teste e Projeto Visando o Teste de Cir-
cuitos e Sistemas Integrados. 2nd.ed. Porto Alegre: Instituto de Informática da UFRGS:
Concepção de Circuitos Integrados, 2002. p.167–189.
MOSER, E.; NEBEL, W. Case study: system model of crane and embedded control.
In: CONFERENCE ON DESIGN, AUTOMATION AND TEST IN EUROPE, Munich,
Germany. Proceedings. . . ACM, 1999. p.139.
MYERS, G. J. The art of software testing. New Jersey, USA: John Wiley & Sons, 2004.
67
WONG, E. W.; RAO, S.; LINN, J. Coverage Testing Embedded Software on Symbian/O-
MAP. In: INTERNATIONAL CONFERENCE ON SOFTWARE ENGINEERING AND
KNOWLEDGE ENGINEERING, 18., San Francisco. Proceedings. . . [S.l.: s.n.], 2006.
1 /∗
∗ A c l a s s e nao pode p e r t e n c e r a um P a c o t e e s p e c i f i c o
∗/
import s a i t o . s a s h i m i . I O I n t e r f a c e ;
import s a i t o . s a s h i m i . F e m t o J a v a I O ;
6 / / import java . io . ∗ ;
p u b l i c c l a s s S o r t T e s t C a s e 1 0 implements I O I n t e r f a c e {
/∗
11 ∗ Todas v a r i a v e i s s a o o b r i g a t o r i a m e n t e e s t a t i c a s
∗/
public s t a t i c int i , j ;
/∗
∗ NUmero de E l e m e n t o s do V e t o r
16 ∗/
p u b l i c s t a t i c i n t MAXELEM = 1 0 ;
/∗
∗ V e t o r com a s e n t r a d a s
∗/
21 p u b l i c s t a t i c i n t [ ] v e t o r D a d o s = {5 ,4 ,3 ,2 ,1 , −1 , −2 , −3 , −4 , −5};
/∗
∗ V a r i a v e i s para o b s e r v a r r e s p o s t a dos t e s t case
∗/
p u b l i c s t a t i c i n t pegou = 0 ;
26 public s t a t i c i n t testMaxElem = 1 ;
public s t a t i c int testOrdenacao = 1;
public s t a t i c int testOrdenacaoParcial = 1;
/∗
∗ Construtor Vazio
31 ∗/
p u b l i c S o r t T e s t C a s e 1 0 ( ) {}
/∗
∗ Todos o m e t o d o s s a o o b r i g a t o r i a m e n t e e s t a t i c o s
∗/
36 p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g v ) {
S o r t T e s t C a s e 1 0 s o r t = new S o r t T e s t C a s e 1 0 ( ) ;
FemtoJavaIO . s e t I O C l a s s ( s o r t ) ;
SortTestCase10 . initSystem () ;
}
41
public s t a t i c void i n i t S y s t e m ( ) {
/ / Chamada d o s T e s t c a s e
/ / S y s t e m . o u t . p r i n t l n ( " TestMaxElem = " + t e s t M a x E l e m ) ;
70
}
51
p u b l i c s t a t i c i n t b u b b l e S o r t ( i n t maxnos ) {
i n t temp ;
91 }
/ / Metodos T e s t C a s e s
public s t a t i c void t e s t I n i t S y s t e m ( ) {
96 i f (MAXELEM ==10) {
testMaxElem = 0 ;
}
/ / S y s t e m . o u t . p r i n t l n ( " TestMaxElem = " + t e s t M a x E l e m ) ;
}
101
71
i f ( v e t o r D a d o s [ i n d e x ] < v e t o r D a d o s [ i n d e x −1]) {
pegou = 1 ;
106 }
i f ( pegou ==0) {
testOrdenacaoParcial = 0;
}
111 / / System . out . p r i n t l n (" testOrdenacaoParcial= " + testOrdenacaoParcial
+ " − > " + v e t o r D a d o s [ i n d e x ]+ " >" + v e t o r D a d o s [ i n d e x −1]) ;
}
p u b l i c s t a t i c v o i d t e s t A f t e r B u b b l e S o r t ( i n t maxElem ) {
f o r ( i = 0 ; i <maxElem −1; i ++) {
116 i f ( v e t o r D a d o s [ i ] <= v e t o r D a d o s [ i + 1 ] ) {
testOrdenacao = 0;
/ / System . out . p r i n t l n (" testOrdenacao = " + testOrdenacao ) ;
} else {
testOrdenacao = 1;
121 / / System . out . p r i n t l n (" testOrdenacao Else = " + testOrdenacao ) ;
}
}
}
126 / / f i m t e s t c a s e s
}
Listing 6.1: Algoritmo de ordenação com os casos de teste selecionados
72
/∗
2 ∗ A c l a s s e nao pode p e r t e n c e r a um P a c o t e e s p e c i f i c o
∗/
import s a i t o . s a s h i m i . I O I n t e r f a c e ;
import s a i t o . s a s h i m i . F e m t o J a v a I O ;
/ / import java . io . ∗ ;
7
p u b l i c c l a s s S o r t T e s t C a s e A l u R e g B a n k T e s t i n g implements I O I n t e r f a c e {
/∗
∗ Todas v a r i a v e i s s a o o b r i g a t o r i a m e n t e e s t a t i c a s
12 ∗/
public s t a t i c int i , j ;
/∗
∗ NUmero de E l e m e n t o s do V e t o r
∗/
17 p u b l i c s t a t i c i n t MAXELEM = 1 0 ;
/∗
∗ V e t o r com a s e n t r a d a s
∗/
p u b l i c s t a t i c i n t [ ] v e t o r D a d o s = {5 ,4 ,3 ,2 ,1 , −1 , −2 , −3 , −4 , −5};
22 /∗
∗ V a r i a v e i s para o b s e r v a r r e s p o s t a dos t e s t case
∗/
p u b l i c s t a t i c i n t pegou = 0 ;
public s t a t i c i n t testMaxElem = 1 ;
27 public s t a t i c int testOrdenacao = 1;
public s t a t i c int testOrdenacaoParcial = 1;
/∗
∗ Construtor Vazio
∗/
32 p u b l i c S o r t T e s t C a s e A l u R e g B a n k T e s t i n g ( ) {}
/∗
∗ Todos o m e t o d o s s a o o b r i g a t o r i a m e n t e e s t a t i c o s
∗/
p u b l i c s t a t i c v o i d main ( S t r i n g [ ] a r g v ) {
37 S o r t T e s t C a s e A l u R e g B a n k T e s t i n g s o r t = new
SortTestCaseAluRegBankTesting ( ) ;
FemtoJavaIO . s e t I O C l a s s ( s o r t ) ;
SortTestCaseAluRegBankTesting . initSystem ( ) ;
}
42 public s t a t i c void i n i t S y s t e m ( ) {
/ / Chamada d o s T e s t c a s e
/ / S y s t e m . o u t . p r i n t l n ( " TestMaxElem = " + t e s t M a x E l e m ) ;
SortTestCaseAluRegBankTesting . t e s t I n i t S y s t e m ( ) ;
/ / System . out . p r i n t l n (" T e s t I n c i a l i z a c a o = " + t e s t I n c i a l i z a c a o ) ;
47 S o r t T e s t C a s e A l u R e g B a n k T e s t i n g . b u b b l e S o r t (MAXELEM) ;
S o r t T e s t C a s e A l u R e g B a n k T e s t i n g . t e s t A f t e r B u b b l e S o r t (MAXELEM) ;
SortTestCaseAluRegBankTesting . aluRegDetTesting ( ) ;
SortTestCaseAluRegBankTesting . regBankTesting ( ) ;
52 }
p u b l i c s t a t i c i n t b u b b l e S o r t ( i n t maxnos ) {
i n t temp ;
/ / Metodos T e s t C a s e s
97 public s t a t i c void t e s t I n i t S y s t e m ( ) {
i f (MAXELEM ==10) {
testMaxElem = 0 ;
}
/ / S y s t e m . o u t . p r i n t l n ( " TestMaxElem = " + t e s t M a x E l e m ) ;
102 }
i f ( v e t o r D a d o s [ i n d e x ] < v e t o r D a d o s [ i n d e x −1]) {
107 pegou = 1 ;
}
i f ( pegou ==0) {
testOrdenacaoParcial = 0;
112 }
/ / System . out . p r i n t l n (" testOrdenacaoParcial= " + testOrdenacaoParcial
+ " − > " + v e t o r D a d o s [ i n d e x ]+ " >" + v e t o r D a d o s [ i n d e x −1]) ;
74
p u b l i c s t a t i c v o i d t e s t A f t e r B u b b l e S o r t ( i n t maxElem ) {
117 f o r ( i = 0 ; i <maxElem −1; i ++) {
i f ( v e t o r D a d o s [ i ] <= v e t o r D a d o s [ i + 1 ] ) {
testOrdenacao = 0;
/ / System . out . p r i n t l n (" testOrdenacao = " + testOrdenacao ) ;
} else {
122 testOrdenacao = 1;
/ / System . out . p r i n t l n (" testOrdenacao Else = " + testOrdenacao ) ;
}
}
127 }
/ / fim t e s t cases
// test RegBank
132 public static int [] results = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
137 };
/ / f i m t e s t RegBank
/ / t e s t ULA
162 public s t a t i c i n t resultsULA []={0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0};
public s t a t i c void aluRegDetTesting ( ) {
i n t operand1 = 0; / / v a l o r i n i c i a l do o p e r a n d o 1 ( 0 x0000 )
i n t operand2 = 0; / / v a l o r i n i c i a l do o p e r a n d o 2 ( 0 x0000 )
int idx = 0;
167
75
w h i l e ( o p e r a n d 2 ! = −2) { / / v a l o r f i n a l do o p e r a n d o 2 ( 0 xFFFE )
w h i l e ( o p e r a n d 1 ! = −2) { / / v a l o r f i n a l do o p e r a n d o 1 ( 0 xFFFE )
resultsULA [ idx ] = operand1 + operand2 ;
i d x ++;
172 resultsULA [ idx ] = operand1 − operand2 ;
i d x ++;
resultsULA [ idx ] = operand1 & operand2 ;
i d x ++;
resultsULA [ idx ] = operand1 | operand2 ;
177 i d x ++;
resultsULA [ idx ] = operand1 ^ operand2 ;
i d x ++;
operand1 = operand1 − 1; / / i n c r e m e n t o do o p e r a n d o 1 ( 0
xFFFF )
}
182 operand1 = 0; / / v a l o r i n i c i a l do o p e r a n d o 1 ( 0 x0000 )
o p e r a n d 2 += −1; / / i n c r e m e n t o do o p e r a n d o 2 ( 0 xFFFF )
}
operand2 = 0; / / v a l o r i n i c i a l do o p e r a n d o 2 ( 0 x0000 )
w h i l e ( o p e r a n d 2 ! = 2 1 8 4 4 ) { / / v a l o r f i n a l do o p e r a n d o 2 ( 0 x5554 )
187 operand2 = operand2 − 1;
resultsULA [ idx ] = operand2 ;
i d x ++;
o p e r a n d 2 = o p e r a n d 2 + 2 1 8 4 5 ; / / i n c r e m e n t o do o p e r a n d o 2 ( 0
x555 )
/ / System . out . p r i n t l n (""+ operand2 ) ;
192 }
}
/ / fim t e s t
197 }
Listing 6.2: Rotinas da biblioteca de auto-teste inseridas ao código do algoritmo de
ordenação com os casos de teste
76
p u b l i c c l a s s Crane {
// static int i ;
3 s t a t i c int testControl = 1;
s t a t i c i n t t e s t R e a d S e n s o r s = 1 , t e s t D i a g n o s i s =1;
public s t a t i c void i n i t S y s t e m ( ) {
/ / f o r ( i =0; i < 1 0 ; i ++) {
Sensor16 . readSensors ( ) ;
8 Sensor16 . testReadSensors ( ) ;
Sensor16 . readSensors ( ) ;
Sensor16 . testReadSensors ( ) ;
Sensor16 . readSensors ( ) ;
Sensor16 . testReadSensors ( ) ;
13 Sensor16 . readSensors ( ) ;
Sensor16 . testReadSensors ( ) ;
Sensor16 . readSensors ( ) ;
Sensor16 . testReadSensors ( ) ;
Control16 . control ( ) ;
18 Control16 . t e s t C o n t r o l ( ) ;
// }
23 p u b l i c s t a t i c v o i d main ( S t r i n g a r g s [ ] ) {
initSystem () ;
}
}
28
i f ( EmergencyStop ) {
i f ( VC_temp ==0)
Crane . t e s t C o n t r o l = 0 ;
43 } else {
i n t num1 = S o f t F l o a t 1 6 . f l o a t 1 6 _ s u b ( u , y ) ;
i f ( S o f t F l o a t 1 6 . f l o a t 1 6 _ l t ( 0 x5100 , num1 ) ! = 1 ) {
i f ( VC_temp== 0 x5100 )
48 Crane . t e s t C o n t r o l = 0 ;
} else i f ( S o f t F l o a t 1 6 . f l o a t 1 6 _ l t ( num1 , 0 xd100 ) ==1) {
i f ( VC_temp== 0 xd100 )
Crane . t e s t C o n t r o l = 0 ;
} else {
53 i f ( VC_temp== num1 )
Crane . t e s t C o n t r o l = 0 ;
}
}
58 }
77
f o r ( i = 0 ; i < 5 ; i ++) {
i f ( ( q [ i ] = = 0 ) | | ( q1 [ i ] = = 0 ) )
Crane . t e s t C o n t r o l = 1 ;
}
63 }
/ / S y s t e m . o u t . p r i n t l n ( " t e s t C o n t r o l = " + Crane . t e s t C o n t r o l ) ;
}
// }
68 p u b l i c c l a s s S e n s o r 1 6 {
/ / c o d i g o do S e n s o r 1 6 nao d e t a l h a d o a q u i . . .
.
.
.
73 p u b l i c s t a t i c v o i d t e s t R e a d S e n s o r s ( ) {
i f ( ( a l f a ==0 x2e66 ) &&( p o s c a r ==0 x3c00 ) ) {
Crane . t e s t R e a d S e n s o r s = 0 ;
}
/ / S y s t e m . o u t . p r i n t l n ( " t e s t R e a d S e n s o r s = " + Crane . t e s t R e a d S e n s o r s ) ;
78
}
public s t a t i c void t e s t D i a g n o s i s ( ) {
i f ( ( c o u n t e r == 0 ) && ( s e n s o r _ w a r n i n g ==0)&&( a l f a _ w a r n i n g ==0) ) {
Crane . t e s t D i a g n o s i s = 0 ;
83 } e l s e i f ( c o u n t e r >=2) {
i f ( a == ( S o f t F l o a t 1 6 . a b s ( 0 x2e66 ) ) ) {
i f ( a l f a _ w a r n i n g >= 2 ) {
i f ( S o f t F l o a t 1 6 . f l o a t 1 6 _ l t ( a , AlfaMax ) ! = 1 )
Crane . t e s t D i a g n o s i s = 0 ;
88 }
}
i f ( s e n s o r _ w a r n i n g >= 2 ) {
i f ( swposcarmax | | s w p o s c a r m i n ) {
Crane . t e s t D i a g n o s i s = 0 ;
93 } else {
Crane . t e s t D i a g n o s i s = 1 ;
}
}
98 }
/ / S y s t e m . o u t . p r i n t l n ( " t e s t D i a g n o s i s = " + Crane . t e s t D i a g n o s i s ) ;
}
}
Listing 6.3: Casos de teste selecionados para o Crane