Asserções em Java: Testando Suposições

JavaBeginner
Pratique Agora

Introdução

Neste laboratório, você aprenderá sobre asserções (assertions) em Java. Aprenderá como criar asserções e quando usá-las. Asserções são usadas para testar suposições em relação ao nosso código e são principalmente utilizadas durante a fase de teste do software.

Criando uma Asserção Simples

Vamos criar uma asserção simples que testa se um número é par. Assumiremos que o número é par e escreveremos uma asserção usando um número par. Em seguida, alteraremos o número e executaremos o código. Deveríamos obter um AssertionError.

public class AssertionsLab {
    public static void main(String[] args) {
        int number = 4;
        assert (number % 2) == 0;
        System.out.println("Number is even");

        // change the value of number variable to odd
        number = 3;
        assert (number % 2) == 0;
        System.out.println("Number is even");
    }
}

Desativando Asserções

Por padrão, as asserções estão desabilitadas em Java. Podemos habilitar as asserções usando opções de linha de comando.

Vamos usar a opção -ea para habilitar as asserções e executar o código.

java -ea AssertionsLab

O código deve imprimir "Number is even" seguido por um AssertionError.

Agora, vamos desabilitar as asserções usando a opção -da e executar o código novamente.

java -da AssertionsLab

O código deve imprimir "Number is even" duas vezes sem lançar nenhuma exceção.

Usando Asserções para Testar Entradas

As asserções também podem ser usadas para testar as entradas de um método. Vamos criar um método divide que recebe dois parâmetros e retorna o quociente após dividir o primeiro parâmetro pelo segundo parâmetro. Assumiremos que o segundo parâmetro é diferente de zero e criaremos uma asserção para verificá-lo.

public class AssertionsLab {
    public static void main(String[] args) {
        int a = 10;
        int b = 5;
        int result = divide(a, b);
        System.out.println("Result: " + result);

        // change the value of b to zero
        b = 0;
        result = divide(a, b);
        System.out.println("Result: " + result);
    }

    private static int divide(int a, int b) {
        assert b != 0 : "Cannot divide by zero";
        return a / b;
    }
}

Usando Asserções para Debugging e Testes

Podemos usar asserções para depuração e testes. Suponha que temos um programa que lê um arquivo e retorna o primeiro número diferente de zero dele. Para testar este programa, vamos criar um arquivo de entrada com três números.

echo "0\n3\n0" > input.txt

Vamos escrever nosso programa que lê o arquivo e retorna o primeiro número diferente de zero dele. Em seguida, criaremos uma asserção para testar se o programa retorna a saída correta.

import java.io.File;
import java.io.FileNotFoundException;
+ import java.util.Scanner;

public class AssertionsLab {
    public static void main(String[] args) throws FileNotFoundException {
        Scanner scanner = new Scanner(new File("input.txt"));
        int number = 0;
        while (scanner.hasNext()) {
            number = scanner.nextInt();
            if (number != 0) {
                break;
            }
        }
        assert number == 3 : "Incorrect number read from file";
        System.out.println("First non-zero number: " + number);
    }
}

Quando Não Usar Asserções

As asserções não são adequadas para validar argumentos de métodos públicos. Essas asserções podem ser desabilitadas durante o tempo de execução, o que pode levar a um comportamento inesperado.

public class AssertionsLab {
    public static void main(String[] args) {
        int negativeNumber = -1;
        printPositiveNumber(negativeNumber);
    }

    public static void printPositiveNumber(int number) {
        assert (number > 0) : "Not a valid positive number";
        System.out.println("Positive number: " + number);
    }
}

Torne as Asserções Informativas

Podemos adicionar mensagens informativas às asserções para torná-las mais informativas e fornecer um feedback melhor em caso de falha. Agora, modificaremos a asserção no código anterior para incluir uma mensagem informativa.

public class AssertionsLab {
    public static void main(String[] args) {
        int number = -1;
        assert (number > 0) : "Negative number found";
        System.out.println("Number is positive: " + number);
    }
}

A mensagem "Negative number found" será exibida quando o código for executado.

Prevenindo Asserções de Quebrar o Código

O propósito das asserções é geralmente encontrar bugs (erros) ao testar software. No entanto, se as próprias asserções quebrarem o código, isso se torna problemático. Por exemplo, um erro de rede transitório ou um problema de timing (tempo) em um sistema pode causar a falha de uma asserção. Adicionalmente, se usarmos asserções para validar entradas em métodos públicos, corremos o risco de deixar nosso sistema desprotegido contra entradas inválidas e maliciosas.

Uma maneira de contornar o impacto negativo das asserções é usá-las com critério. Use asserções apenas para coisas que nunca deveriam acontecer em um sistema bem projetado.

public class AssertionsLab {
    public static void main(String[] args) {
        double result = squareRoot(4);
        System.out.println("Square root: " + result);

        double negativeNumber = -4;
        result = squareRoot(negativeNumber);
        System.out.println("Square root: " + result);
    }

    public static double squareRoot(double number) {
        assert number >= 0 : "Number should be non-negative";
        return Math.sqrt(number);
    }
}

Evitando Efeitos Colaterais

É importante evitar efeitos colaterais ao usar asserções. Devemos evitar a alteração de variáveis dentro das asserções. Em vez disso, as expressões devem ser usadas para detectar situações problemáticas e fornecer mais informações de diagnóstico.

public class AssertionsLab {
    public static void main(String[] args) {
        int firstNumber = 1;
        int secondNumber = 2;
        assert (firstNumber = secondNumber) == 0 : "Values are not equal";
        System.out.println("Values are equal");
    }
}

Usando Asserções para Verificar Instruções Switch

Podemos usar asserções para verificar se todos os casos possíveis de uma instrução switch foram cobertos. Vamos criar uma instrução switch que retorna o nome de um dia com base em seu número. Assumiremos que o número está dentro do intervalo de 0 a 6 e criaremos uma asserção para verificá-lo.

public class AssertionsLab {
    public static void main(String[] args) {
        int dayNumber = 2;
        String day = getDayName(dayNumber);
        System.out.println("Day: " + day);

        // set dayNumber to an invalid number
        dayNumber = 10;
        day = getDayName(dayNumber);
        System.out.println("Day: " + day);
    }

    public static String getDayName(int dayNumber) {
        String day;
        switch (dayNumber) {
            case 0:
                day = "Sunday";
                break;
            case 1:
                day = "Monday";
                break;
            case 2:
                day = "Tuesday";
                break;
            case 3:
                day = "Wednesday";
                break;
            case 4:
                day = "Thursday";
                break;
            case 5:
                day = "Friday";
                break;
            case 6:
                day = "Saturday";
                break;
            default:
                assert false : "Invalid day number";
        }
        return day;
    }
}

Resumo

Parabéns! Você concluiu o laboratório de Asserções em Java. Você pode praticar mais laboratórios no LabEx para aprimorar suas habilidades.