%cabeçalho para todos os capítulos
%\input{cabecalho}

%\begin{document}

%Opções para o pacote listings
%\input{listingOptions}

\chapter{Testes Automatizados}

\begin{center}
\shabox{
  \begin{Bitemize}
    \item[]\textbf{Quais novidades veremos nesta aula?}
    \item comando \texttt{if} e \texttt{else};
    \item comparações \texttt{==} (igualdade) e \texttt{!=} (diferença);
    \item definição de variáveis inteiras e de ponto flutuante.
    \item impressão de texto.
    \end{Bitemize}
} % \shabox
\end{center}
\bigskip

\section{Testes}

Desde o início, a computação sempre esteve sujeita erros. O termo
\emph{bug}, para denotar erro, tem uma origem muito anterior (vem
de um inseto que causava problemas de leitura no fonográfo de Thomas
Edison em 1889). Várias outras histórias reais, ou nem tanto, também
apareceram no início da informática. Infelizmente, é muito difícil
garantir que não existam erros em programas. Uma das formas de se
garantir que certos erros não vão ocorrer é testando algumas situações.

Apesar da frase célebre de Edsger Dijsktra que testes podem apenas
mostrar a presença de erros, e não a sua ausência, eles podem ser
os nossos grandes aliados no desenvolvimento de programas corretos.
Logo, intuitivamente, quanto mais testes fizermos em um programa,
mais confiantes podemos ficar com relação ao seu funcionamento. Por
outro lado, nós podemos usar o próprio computador para nos ajudar,
isto é, podemos criar testes automatizados. Ao invés de fazermos os
testes ``na mão'', faremos com que o computador seja
capaz de verificar o funcionamento de uma seqüência de testes. Veremos
nesta aula como desenvolver testes automatizados, passo a passo, para
os conversores de temperatura vistos anteriormente.

No início da computação não havia uma preocupação muito grande com os testes,
eles eram feitos de forma manual pelos próprios programadores, os grandes
testadores eram os usuários finais. É interessante notar que isto ainda
acontece com alguns produtos ainda hoje. Com o aparecimento da Engenharia de
Software ficou clara a necessidade de se efetuar testes, tanto que em várias
empresas de desenvolvimento de software existe a figura do testador,
responsável por tentar encontrar erros em sistemas. Hoje existe uma tendência
em se considerar que testes automatizados são muito importantes, devendo ser
escritos mesmo antes de se escrever o código propriamente dito, técnica esta
chamada de \emph{testes a priori}.

Veremos como testar os diversos conversores de temperatura. Como testar
o nosso primeiro programa em Java (Conversor).

\begin{lstlisting}
Conversor c1 = new Conversor()

// a resposta esperada é o equivalente a 40C em F
if (c1.celsiusParaFahrenheit() == 104)
  System.out.println("Funciona");
else
  System.out.println("Não funciona");
\end{lstlisting}

Note que para fazer o teste utilizamos o comando condicional \texttt{if
  else}. O formato genérico deste comando é o seguinte.

\begin{lstlisting}
if (CONDIÇÃO)
  COMANDO-1;
else
  COMANDO-2;
\end{lstlisting}

Se a \texttt{CONDIÇÃO} é verdadeira, o \texttt{COMANDO-1} é executado, caso
contrário, o \texttt{COMANDO-2} é executado.

A classe \texttt{Conversor2} possui um método que aceita um parâmetro, veja o
teste abaixo:

\begin{lstlisting}
Conversor2 c2 = new Conversor2();

// cria duas variáveis inteiras
int entrada = 40;
int resposta = 104;

// a resposta esperada é o equivalente a entrada C em F
if (c2.celsiusParaFahrenheit(entrada) == resposta)
  System.out.println("Funciona");
else
  System.out.println("Não funciona");
\end{lstlisting}

Note que, para realizar o teste acima nós definimos duas variáveis inteiras
chamadas de \texttt{entrada} e \texttt{resposta}. A linha 
\begin{lstlisting}
int entrada = 40;
\end{lstlisting}
faz na verdade duas coisas. Primeiro, ela declara a criação de uma nova
variável (\texttt{int entrada;}) e, depois, atriubui um valor inicial a esta
variável (\texttt{entrada = 40;}). Na linguagem Java, se o valor inicial não é
atribuído, o sistema atribui  valor 0 automaticamente.

Podemos também testar o \texttt{Conversor2} para outros valores. Por exemplo,
para as entradas e respostas: 20 (68) e 100 (212).

\begin{lstlisting}
entrada = 20; // como as variáveis já foram declaradas acima, basta usá-las
resposta = 68;
if (c2.celsiusParaFahrenheit(entrada) == resposta)
  System.out.println("Funciona");
else
  System.out.println("Não funciona");

entrada = 100;
resposta = 212;
if (c2.celsiusParaFahrenheit(entrada) == resposta)
  System.out.println("Funciona");
else
  System.out.println("Não funciona");
\end{lstlisting}

No programa acima o texto \emph{Funciona} vai ser impresso na tela a cada
sucesso, isso poderá causar uma poluição visual caso tenhamos dezenas ou
centenas de testes. O ideal para um testador é que ele fique silencioso caso
os testes dêem certo e chame a atenção caso ocorra algum erro. Podemos então
mudar o programa para:

\begin{lstlisting}
Conversor2 c2 = new Conversor2();

int entrada = 40;
int resposta = 104;
if (c2.celsiusParaFahrenheit(entrada) != resposta)
  System.out.println("Não funciona para 40");

entrada = 20;
resposta = 68;
if (c2.celsiusParaFahrenheit(entrada) != resposta)
  System.out.println("Não funciona para 20");

entrada = 100;
resposta = 212;
if (c2.celsiusParaFahrenheit(entrada) != resposta)
  System.out.println("Não funciona para 100");

System.out.println("Fim dos testes");
\end{lstlisting}

Note que o comando \texttt{if} acima foi utilizado sem a parte do \texttt{else}
o que é perfeitamente possível. Adicionamos também uma linha
final para informar o final dos testes. Ela é importante no caso em que todos
os testes dão certo para que o usuário saiba que já terminamos a execução de
todos os testes.

Uma forma de simplificar os comandos de impressão é usar a própria entrada
como parâmetro, isto pode ser feito da seguinte forma:

\begin{lstlisting}
System.out.println("Não funciona para " + entrada);
\end{lstlisting}

Criaremos agora os testes para o \texttt{Conversor4}. Mas agora, devem ser
testados os seus dois métodos. Introduziremos um testador automático
criando uma classe com apenas um método que faz o que vimos.

\begin{lstlisting}
class TestaConversor4
{
  int testaTudo()
  {
    Conversor4 c4 = new Conversor4();
    double tc = 10.0;
    double tf = 50.0;

    if (c4.celsiusParaFahrenheit(tc) != tf)
      System.out.println("C-> F não funciona para " + tc);
    if (c4.fahrParaCelsius(tf) != tc)
      System.out.println("F-> C não funciona para " + tf);
    tc = 20.0;
    tf = 68.0;
    if (c4.celsiusParaFahrenheit(tc) != tf)
      System.out.println("C-> F não funciona para " + tc);
    if (c4.fahrParaCelsius(tf) != tc)
      System.out.println("F-> C não funciona para " + tf);
    tc = 101.0;
    tf = 213.8;
    if (c4.celsiusParaFahrenheit(tc) != tf)
      System.out.println("C-> F não funciona para " + tc);
    if (c4.fahrParaCelsius(tf) != tc)
      System.out.println("F-> C não funciona para " + tf);
    System.out.println("Final dos testes");
    return 0;
  }
}
\end{lstlisting}

%-------------------- Exercícios ----------------------------

Agora, vamos treinar o que aprendemos com alguns exercícios. Em particular, o
exercício 3 de refatoração é muito importante.

\section{Exercícios}

\begin{enumerate}
  
\item Escreva uma classe \texttt{Olá} com um único método \texttt{cumprimenta}
  que, a cada chamada, cumprimenta o usuário de uma entre 3 maneiras
  diferentes.  \emph{Dica:} use um atributo para, dependendo de seu valor,
  escolher qual das maneiras será usada; depois de imprimir a mensagem, altere
  o valor do atributo.

% Exercício 1
\item Escreva uma classe \texttt{TestaConversor3} para testar a classe \texttt{Conversor3}.

% Exercício 2
\item Refatorar a classe \texttt{TestaConversos4} de modo a eliminar as partes
repetidas do código. \emph{Dica:} Crie um método que realiza o teste das duas funções.

% Exercício 3
\item Podemos criar testes para objetos de uma classe que não sabemos como
foi implementada. Para tal, basta conhecermos suas entradas e saídas. \\
Escreva um teste automatizado para a seguinte classe:

\begin{lstlisting}
class Contas
{
  double calculaQuadrado(double x);
  double calculaCubo(double x);
}
\end{lstlisting}

% Exercício 4
\item \emph{Programas confiáveis:} Se conhecemos uma implementação e
sabemos que a mesma funciona de maneira confiável, ela pode servir de
base para o teste de outras implementações. Caso duas implementações diferentes
produzam resultados distintos para os mesmos dados de entrada, podemos
dizer que pelo menos uma das duas está errada; \\
Supondo que a classe \texttt{Contas} do exercício anterior é confiável,
escreva um teste automatizado que utiliza esta classe para testar a classe
\texttt{ContasNaoConfiavel} dada abaixo:

\begin{lstlisting}
class ContasNaoConfiavel
{
  double calculaQuadrado(double x);
  double calculaCubo(double x);
}
\end{lstlisting}

\end{enumerate}

%-------------------- Resoluções ----------------------------
\section{Resoluções}

\begin{enumerate}

%Exercício 3
\item[3] ~

\begin{lstlisting}
int testePontual(double tc, double tf)
{
  Conversor c4 = new Conversor4();

  if (c4.celsiusParaFahrenheit(tc) != tf)
    System.out.println("C-> F não funciona para " + tc);
  if (c4.fahrParaCelsius(tf) != tc)
    System.out.println("F-> C não funciona para " + tf);
  return 0;
}

int testaTudo()
{
  double tc = 10.0;
  double tf = 50.0;
  testePontual(tc, tf);
  tc = 20.0;
  tf = 68.0;
  testePontual(tc, tf);
  tc = 101.0;
  tf = 213.8;
  testePontual(tc, tf);
  System.out.println("Final dos testes");
  return 0;
}
\end{lstlisting}

% Exercício 4
\item[4] ~

\begin{lstlisting}
Contas a = new Contas();
double x = 4.0;

if (a.calculaQuadrado(x) != 16.0)
  System.out.println("Não funciona para calcular o quadrado de 4");
if (a.calculaCubo(x) != 64.0)
  System.out.println("Não funciona para calcular 4 ao cubo");
\end{lstlisting}


\end{enumerate}

%\end{document}
