Testes Unitários em Java Laboratório de Programação Pedro Vasconcelos, Manuel Barbosa, DCC/FCUP Março 2016 Pedro Vasconcelos, Manuel Barbosa, DCC/FCUP Testes Unitários em Java Testes Unitários uma unidade pode ser uma função, uma classe um package ou um sub-sistema. cada teste unitário tem como objectivo verificar uma propriedade comportamental de uma unidade uma propriedade pode ser muito simples a consistência de métodos get/set ou mais complexa a preservação de um invariante numa sequência longa de operações. Pedro Vasconcelos, Manuel Barbosa, DCC/FCUP Testes Unitários em Java Cobertura e repetibilidade A cobertura é a percentagem das linhas de código que um conjunto de testes estimula. Em teoria deveria aproximar-se de 100%, mas é necessário pesar o esforço de criação e manutenção dos próprios testes. A repetição dos testes frequentemente ao longo do desenvolvimento permite garantir que propriedades já estabelecidas não são perturbadas por alterações posteriores. Pedro Vasconcelos, Manuel Barbosa, DCC/FCUP Testes Unitários em Java JUnit O JUnit é a plataforma mais popular para gestão e execução de testes unitários em Java. É muito utilizado na indústria Pode ser utilizado da linha de comando ou integrado em IDE, e.g., IntelliJ Pode ser utilizado para testar: Um objecto. Parte de um objecto - um ou mais métodos relacionados. Interacção entre vários objectos. Pedro Vasconcelos, Manuel Barbosa, DCC/FCUP Testes Unitários em Java Funcionalidades JUnit Asserções para testar resultados de diversos tipos Mecanismos para partilha de dados de teste Agregação e estruturação de conjuntos de testes Execução de testes com interfaces textuais e gráficas Pedro Vasconcelos, Manuel Barbosa, DCC/FCUP Testes Unitários em Java Exemplo simples Começamos com a seguinte classe com um único método. public class Calcular { public int soma(int a, int b) { System.out.println("A somar: "+a+"+"+b); return a + b; } } Pedro Vasconcelos, Manuel Barbosa, DCC/FCUP Testes Unitários em Java Primeiro teste unitário import static org.junit.Assert.*; import org.junit.Test; public class CalculateTest { @Test public void testSoma() { Calcular calculo = new Calcular(); int s = calculo.soma(2, 5); int r = 7; // resposta esperada System.out.println( "@Test soma():" + s + " = " + r ); assertEquals(s, r); } } Pedro Vasconcelos, Manuel Barbosa, DCC/FCUP Testes Unitários em Java Pontos importantes A anotação @Test identifica o método testSoma como sendo um teste que o JUnit deve executar Numa classe podemos ter vários métodos anotados como @Test. A função assertEquals recebe dois objectos ou valores nativos e utiliza comparação directa ou o método equals para os comparar e verificar que são iguais. Há duas formas de executar um teste: Escrever uma classe de execução de teste utilizando os mecanismos oferecidos pelo JUnit Tirando partido da integração do JUnit num IDE, tal como acontece no IntelliJ. Pedro Vasconcelos, Manuel Barbosa, DCC/FCUP Testes Unitários em Java Outras anotações JUnit Todos os métodos anotados são do tipo public void e não recebem parâmetros. Executado antes de cada teste na classe. (E.g., inicialização de estado para teste.) @BeforeClass Método estático executado uma única vez antes de qualquer outra operação. (E.g. ligação a uma BD.) @After Executado depois de cada teste na classe. (E.g., limpeza de estruturas temporárias.) @AfterClass Método estático que deve ser executado uma única vez quando todos os testes tiverem sido executados. (E.g., desligar de BD.) @Before Pedro Vasconcelos, Manuel Barbosa, DCC/FCUP Testes Unitários em Java Outras asserções JUnit Verifica que uma condição é verdadeira. Verifica que uma condição é falsa. Verifica que uma referência não é null. Verifica que uma referência é null. Verifica que duas referências apontam para o mesmo objecto. assertNotSame Verifica que duas referências não apontam para o mesmo objecto. assertArrayEquals Verifica que os conteúdos de dois arrays são iguais. assertTrue assertFalse assertNotNull assertNull assertSame Pedro Vasconcelos, Manuel Barbosa, DCC/FCUP Testes Unitários em Java Automação de testes no JUnit Por omissão, o JUnit executa apenas os testes definidos numa única classe de testes. Podemos agrupar várias classes de testes numa só definindo uma “suite” de testes. Também podemos definir testes parametrizados em que o mesmo teste é executado para uma lista de valores de entrada e correspondentes resultados esperados. A anotação @RunWith permite identificar o motor de automação Suite.class ou Parametrized.class que deverá ser utilizado para correr os testes. Pedro Vasconcelos, Manuel Barbosa, DCC/FCUP Testes Unitários em Java Exemplo de automação Suite import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ ClasseTeste1.class, ClasseTeste2.class }) public class AllTests { /* Classe vazia apenas para agrupar todos os testes de `ClasseTeste1' e `ClasseTeste2' */ } Pedro Vasconcelos, Manuel Barbosa, DCC/FCUP Testes Unitários em Java Executar testes na linha de comando A classe org.junit.runner.JUnitCore permite invocar o motor do JUnit a partir de uma classe Java que seja criada para esse efeito. O método runClasses() recebe uma classe de teste como argumento e retorna um valor do tipo Result. O valor retornado contém uma lista de resultados que permite determinar o sucesso/insucesso de cada teste. Pedro Vasconcelos, Manuel Barbosa, DCC/FCUP Testes Unitários em Java Exemplo import org.junit.runner.JUnitCore; import org.junit.runner.Result; import org.junit.runner.notification.Failure; public class JunitRunner { public static void main(String[] args) { Result result = JUnitCore.runClasses(AllTests.class); for (Failure fail : result.getFailures()) System.out.println(fail.toString()); if (result.wasSuccessful()) System.out.println("Todos os testes OK."); } } Pedro Vasconcelos, Manuel Barbosa, DCC/FCUP Testes Unitários em Java